<exclude name="MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.SingleSpaceBeforeSingleLineComment" />
<exclude name="MediaWiki.Usage.DbrQueryUsage.DbrQueryFound" />
<exclude name="MediaWiki.Usage.ExtendClassUsage.FunctionVarUsage" />
- <exclude name="MediaWiki.Usage.ForbiddenFunctions.assert" />
<exclude name="MediaWiki.Usage.SuperGlobalsUsage.SuperGlobals" />
<exclude name="MediaWiki.Files.ClassMatchesFilename.WrongCase" />
<exclude name="MediaWiki.Files.ClassMatchesFilename.NotMatch" />
grunt.loadNpmTasks( 'grunt-jsonlint' );
grunt.loadNpmTasks( 'grunt-karma' );
grunt.loadNpmTasks( 'grunt-stylelint' );
- grunt.loadNpmTasks( 'grunt-webdriver' );
karmaProxy[ wgScriptPath ] = {
target: wgServer + wgScriptPath,
'!resources/lib/**',
'!resources/src/jquery.tipsy/**',
'!resources/src/jquery/jquery.farbtastic.js',
- '!resources/src/mediawiki.libs/**',
+ '!resources/src/mediawiki.libs.jpegmeta/**',
// Third-party code of PHPUnit coverage report
'!tests/coverage/**',
'!vendor/**',
return require( 'path' ).join( dest, src.replace( 'resources/', '' ) );
}
}
- },
-
- // Configure WebdriverIO task
- webdriver: {
- test: {
- configFile: './tests/selenium/wdio.conf.js'
- }
}
-
} );
grunt.registerTask( 'assert-mw-env', function () {
MediaWiki 1.31 is an alpha-quality branch and is not recommended for use in
production.
-=== Important pre-upgrade notes for 1.31 ===
-* If you're using MySQL, SQLite, or MSSQL, are not using update.php to apply
- schema changes, and cannot have downtime to run migrateArchiveText.php and
- apply patch-drop-ar_text.sql manually, you'll have to apply a default value
- to the ar_text and ar_flags columns of the archive table or make those
- columns nullable before upgrading to MediaWiki 1.31.
- maintenance/archives/patch-nullable-ar_text.sql shows how to do this for MySQL.
-
=== Configuration changes in 1.31 ===
* $wgEnableAPI and $wgEnableWriteAPI are now deprecated and will be removed in
a future version. The API is now considered to be stable, secure and
essential.
-* $wgUsejQueryThree was removed, as it is now the default. This was documented as a
- temporary variable during the migration period, deprecated since 1.29.
+* $wgUsejQueryThree was removed, as it is now the default. This was documented
+ as a temporary variable during the migration period, deprecated since 1.29.
* $wgLogoHD has been updated to support svg images and uses $wgLogo where
possible for fallback images such as png.
-* (T44246) $wgFilterLogTypes will no longer ignore 'patrol' when user does
- not have the right to mark things patrolled.
+* (T44246) $wgFilterLogTypes will no longer ignore 'patrol' when user does not
+ have the right to mark things patrolled.
* Wikis that contain imported revisions or CentralAuth global blocks should run
maintenance/cleanupUsersWithNoId.php.
-* $wgResourceLoaderMinifierStatementsOnOwnLine and $wgResourceLoaderMinifierMaxLineLength
- were removed (deprecated since 1.27).
-* (T180921) $wgReferrerPolicy now supports having fallbacks for browsers that are not
- using the latest version of the Referrer Policy specification.
-* $wgFragmentMode is now set to [ 'legacy', 'html5' ] by default. This is a first step of
- migration to human-readable section IDs that will later result in 'html5' being the
- default mode.
+* The configuration settings $wgResourceLoaderMinifierStatementsOnOwnLine and
+ $wgResourceLoaderMinifierMaxLineLength, deprecated since 1.27, were removed.
+* (T180921) $wgReferrerPolicy now supports having fallbacks for browsers that
+ are not using the latest version of the Referrer Policy specification.
+* $wgFragmentMode is now set to [ 'legacy', 'html5' ] by default. This is a
+ first step of migration to human-readable section IDs that will later result
+ in 'html5' being the default mode.
* CACHE_ACCEL now only supports APC(u) or WinCache. XCache support was removed
as upstream is inactive and has no plans to move to PHP 7.
* The old CategorizedRecentChanges feature, including its related configuration
option $wgAllowCategorizedRecentChanges, has been removed.
-* (T188472) The 'comma' value for $wgArticleCountMethod is no longer supported for
- performance reasons, and installations with this setting will now work as if it
- was configured with 'any'.
-* (T185753) MediaWiki now defaults to using RemexHtml to tidy up user input, rather than
- being off by default. If you wish to disable HTML tidying entirely, set $wgTidyConfig
- to null; if you wish to use the old, deprecated Tidy external binary, both
- set $wgTidyConfig to null and also set $wgUseTidy to true.
+* (T188472) The 'comma' value for $wgArticleCountMethod is no longer supported
+ for performance reasons, and installations with this setting will now work as
+ if it was configured with 'any'.
+* (T185753) MediaWiki now defaults to using RemexHtml to tidy up user input,
+ rather than being off by default. If you wish to disable HTML tidying
+ entirely, set $wgTidyConfig to null; if you wish to use the old, deprecated
+ Tidy external binary, both set $wgTidyConfig to null and $wgUseTidy to true.
* $wgLogAutopatrol now defaults to false instead of true.
* $wgValidateAllHtml was removed and will be ignored.
-* $wgScriptExtension was removed (deprecated and ignored since 1.25).
- See 1.25 release notes for more information.
+* $wgScriptExtension, deprecated and ignored since 1.25, was removed. See the
+ 1.25 release notes for more information.
* $wgUseAjax is now marked as deprecated, just like the deprecated AJAX
framework that it enables. Some extensions mistakenly used this to check
whether any AJAX functionality at all should be enabled, further making this
problematic to retain.
=== New features in 1.31 ===
-* (T76554) User sub-pages named ….json are now protected in the same way that ….js
- and ….css pages are, so that configuration options can safely be placed there.
-* Wikimedia\Rdbms\IDatabase->select() and similar methods now support
- joins with parentheses for grouping.
+* (T76554) User sub-pages named ….json are now protected in the same way that
+ ….js and ….css pages are, so that configuration options can safely be placed
+ there.
+* Wikimedia\Rdbms\IDatabase->select() and similar methods now support joins
+ with parentheses for grouping.
* As a first pass in standardizing dialog boxes across the MediaWiki product,
- Html class now provides helper methods for messageBox, successBox, errorBox and
- warningBox generation.
+ Html class now provides helper methods for messageBox, successBox, errorBox
+ and warningBox generation.
* (T9240) Imports will now record unknown (and, optionally, known) usernames in
a format like "iw>Example".
* (T20209) Linker (used on history pages, log pages, and so on) will display
soon as any necessary extensions are updated.
* Most code accessing rows for logged actions from the database should use
the relevant getQueryInfo() methods to get the information needed to build
- the SQL query. The ActorMigration class may also be used to get feature-flagged
- information needed to access actor-related fields during the migration
- period.
+ the SQL query. The ActorMigration class may also be used to get feature
+ -flagged information needed to access actor-related fields during the
+ migration period.
* Added Wikimedia\Rdbms\IDatabase::cancelAtomic(), to roll back an atomic
section without having to roll back the whole transaction.
* Wikimedia\Rdbms\IDatabase::doAtomicSection(), non-native ::insertSelect(),
extensions. Pass --with-extensions to enable that feature.
* (T184791) rc_patrolled now has three states: "0" for unpatrolled,
"1" for manually patrolled and "2" for autopatrolled actions.
-* Extensions can now set their type to "editor" if they provide an editor
- or enhance the editing experience.
-* Extensions can use a PSR-4 autoloader by setting an "AutoloadNamespaces" property
- in extension.json. See
- <https://www.mediawiki.org/wiki/Manual:Extension.json/Schema#AutoloadNamespaces>
+* Extensions can now set their type to "editor" if they provide an editor or
+ enhance the editing experience.
+* Extensions can use a PSR-4 autoloader by setting an "AutoloadNamespaces"
+ property in extension.json. See the documentation at
+ <https://mediawiki.org/wiki/Manual:Extension.json/Schema#AutoloadNamespaces>
for more details and an example.
+* (T19099) Tabs which link to pages that don't exist (like those to uncreated
+ discussion pages) now have a tooltip to indicate state, not just colour.
=== External library changes in 1.31 ===
==== Upgraded external libraries ====
* Updated jquery.chosen from v0.9.14 to v1.8.2.
-* Updated composer/spdx-licenses from 1.1.4 to
- 1.3.0 (development dependency).
-* Updated nikic/php-parser from 2.1.0 to 3.1.3
- (development dependency).
+* Updated composer/spdx-licenses from 1.1.4 to 1.3.0 (development dependency).
+* Updated nikic/php-parser from 2.1.0 to 3.1.3 (development dependency).
* Updated wikimedia/ip-set from 1.1.0 to 1.2.0.
* Updated wikimedia/relpath from 2.0.0 to 2.1.1.
* Updated wikimedia/running-stat from 1.1.0 to 1.2.0.
* Updated mediawiki/at-ease from 1.1.0 to 1.2.0.
* Updated wikimedia/php-session-serializer from 1.0.4 to 1.0.6.
* Updated wikimedia/remex-html from 1.0.2 to 1.0.3.
-* …
+* Updated wikimedia/html-formatter from 1.0.1 to 1.0.2.
==== New external libraries ====
* Added wikimedia/object-factory 1.0.0
-* …
==== Removed and replaced external libraries ====
* (T17845) The deprecated 'jquery.badge' module was removed.
* The deprecated 'jquery.placeholder' module was removed.
* The deprecated 'jquery.appear' module was removed. Use the
'mediawiki.viewport' module instead.
-* The deprecated 'mediawiki.widgets.CategorySelector' module alias was removed.
- Use the 'mediawiki.widgets.CategoryMultiselectWidget' module directly instead.
* mediawiki/at-ease was replaced with wikimedia/at-ease.
=== Bug fixes in 1.31 ===
* (T90902) Non-breaking space in header ID breaks anchor.
-* (T189375) CSSMin now allows quoted urls in `url()` syntax to start with a space.
+* (T189375) CSSMin now allows quoted urls in `url()` syntax to start with a
+ space.
+* (T2087, T10897, T87753, T174639) Whitespace created by category and language
+ links is now stripped rather than leaving blank lines in odd places.
+* (T3780) Uploads with UTF-8 names now work on PHP7.1+ on Windows servers.
=== Action API changes in 1.31 ===
* (T185058) The 'name' value to tgprop for action=query&list=tags has been
removed. It has never made a difference in the output, the name was always
returned regardless.
-* The 'watch' and 'unwatch' parameters for action=move have been removed. They
- were deprecated and also accidentally nonfunctional since 1.17 in 2010. Use
+* The 'watch' and 'unwatch' parameters for action=move have been removed. They
+ were deprecated and also accidentally nonfunctional since 1.17 in 2010. Use
'watchlist' instead.
=== Action API internal changes in 1.31 ===
-* ApiBase::getProfileDBTime was removed (deprecated since 1.25)
-* ApiBase::getModuleProfileName was removed (deprecated since 1.25)
-* ApiBase::getProfileTime was removed (deprecated since 1.25)
+* ApiBase::getProfileDBTime, deprecated since 1.25, was removed.
+* ApiBase::getModuleProfileName, deprecated since 1.25, was removed.
+* ApiBase::getProfileTime, deprecated since 1.25, was removed.
=== Languages updated in 1.31 ===
MediaWiki supports over 350 languages. Many localisations are updated
regularly. Below only new and removed languages are listed, as well as
changes to languages because of Phabricator reports.
-* (T180052) Mirandese (mwl) now supports gendered NS_USER/NS_USER_TALK namespaces.
+* (T180052) Mirandese (mwl) now supports gendered NS_USER/NS_USER_TALK.
* (T182305) New language support: Nyungar (nys).
* (T186359) New language support: Siberian Tatar [cебертатар] (sty).
* (T186635) New language support: Guianan Creole (gcr).
* (T189127) New language support: Gorontalo (gor).
=== Breaking changes in 1.31 ===
-* MessageBlobStore::insertMessageBlob() (deprecated in 1.27) was removed.
-* The OutputPage class constructor now requires a context parameter,
- (instantiating without context was deprecated in 1.18)
-* The mw.page JavaScript singleton (deprecated in 1.30) was removed.
+* MessageBlobStore::insertMessageBlob(), deprecated in 1.27, was removed.
+* The OutputPage class constructor now requires a context parameter.
+ Instantiating without context was deprecated in 1.18.
+* The mw.page JavaScript singleton, deprecated in 1.30, was removed.
* Article::getLastPurgeTimestamp(), WikiPage::getLastPurgeTimestamp(), and the
related WikiPage::PURGE_* constants, deprecated in 1.29, were removed.
-* The Article::selectFields(), Article::onArticleCreate(),
- Article::onArticleDelete(), and Article::onArticleEdit() methods, deprecated
- in 1.24, were removed.
-* Installer::locateExecutable() and Installer::locateExecutableInDefaultPaths()
- were removed, use ExecutableFinder::findInDefaultPaths() instead.
+* The Article::selectFields(), ::onArticleCreate(), ::onArticleDelete(), and
+ ::onArticleEdit() methods, deprecated in 1.24, were removed.
+* Installer::locateExecutable() and ::locateExecutableInDefaultPaths() were
+ removed. Use ExecutableFinder::findInDefaultPaths() instead.
* The deprecated MW_DIFF_VERSION constant was removed.
DifferenceEngine::MW_DIFF_VERSION should be used instead.
* Due to significant refactoring, method ContribsPager::getUserCond() that had
* The Block class will no longer accept usable-but-missing usernames for
'byText' or ->setBlocker(). Callers should either ensure the blocker exists
locally or use a new interwiki-format username like "iw>Example".
-* The following methods and constants from the WatchedItem class, which were deprecated in
- 1.27, have been removed.
+* The following methods and constants from the WatchedItem class, which were
+ deprecated in 1.27, have been removed:
* WatchedItem::getTitle()
* WatchedItem::fromUserTitle()
* WatchedItem::addWatch()
* WatchedItem::CHECK_USER_RIGHTS
* WatchedItem::DEPRECATED_USAGE_TIMESTAMP
* The $statementsOnOwnLine parameter of JavaScriptMinifier::minify was removed.
- The corresponding configuration variable ($wgResourceLoaderMinifierStatementsOnOwnLine)
- has been deprecated since 1.27 and was removed as well.
+ $wgResourceLoaderMinifierStatementsOnOwnLine, the corresponding configuration
+ variable, has been deprecated since 1.27 and was removed as well.
* The $maxLineLength parameter of JavaScriptMinifier::minify was removed.
- The corresponding configuration variable ($wgResourceLoaderMinifierMaxLineLength)
- has been deprecated since 1.27 and was removed as well.
-* The HtmlFormatter class was removed (deprecated in 1.27). The namespaced
+ $wgResourceLoaderMinifierMaxLineLength, the corresponding configuration
+ variable, has been deprecated since 1.27 and was removed as well.
+* The HtmlFormatter class, deprecated in 1.27, was removed. The namespaced
HtmlFormatter\HtmlFormatter class should be used instead.
* The driver 'mysql' for MySQL, deprecated in MediaWiki 1.30, has been removed.
The driver has been deprecated since PHP 5.5 and was removed in PHP 7.0. The
default driver for MySQL has been 'mysqli' since MediaWiki 1.22.
-* The following properties of PreparedEdit were deprecated in 1.21 and have been removed:
+* The following properties of PreparedEdit were deprecated in 1.21 and have
+ been removed:
* PreparedEdit->newText
* PreparedEdit->oldText
* PreparedEdit->pst
-* ParserOutput objects generated using a non-default value for
- ParserOptions::setWrapOutputClass() can no longer be added to the parser cache.
+* ParserOutput objects which are generated using a non-default value for
+ ParserOptions::setWrapOutputClass() can no longer be added to the parser
+ cache.
* The following deprecated methods from the OutputPage class have been removed:
* OutputPage::addExtensionStyle(); deprecated in 1.27
* OutputPage::getExtStyle(); deprecated in 1.27
* OutputPage::setSquidMaxage(); deprecated in 1.27
* OutputPage::readOnlyPage(); deprecated in 1.25
* OutputPage::rateLimited(); deprecated in 1.25
- * Additionally, the protected OutputPage::$mExtStyles array, only accessed through
- the above and with no known uses, was removed.
+ * Additionally, the protected OutputPage::$mExtStyles array, only accessed
+ through the above and with no known uses, was removed.
* The no-op method Skin::showIPinHeader(), deprecated in 1.27, was removed.
-* The following variables and methods in EditPage, deprecated in MediaWiki 1.30, were removed:
+* The following variables and methods in EditPage, deprecated in MediaWiki 1.30,
+ were removed:
* $isCssJsSubpage — use ::isUserConfigPage()
* $isCssSubpage — use ::isUserCssConfigPage()
* $isJsSubpage — use ::isUserJsConfigPage()
- * $isWrongCaseCssJsPage – use ::isWrongCaseUserConfigPage()
- * ::getSummaryInput() – use ::getSummaryInputWidget()
- * ::getSummaryInputOOUI() – use ::getSummaryInputWidget()
- * ::getCheckboxes() – use ::getCheckboxesWidget() or ::getCheckboxesDefinition()
- * ::getCheckboxesOOUI() – use ::getCheckboxesWidget() or ::getCheckboxesDefinition()
-* The method ResourceLoaderModule::getPosition(), deprecated in 1.29, has been removed.
-* In User, the cookie-related methods which were wrappers for the functions on the response
- object, and were deprecated in 1.27, have been removed:
+ * $isWrongCaseCssJsPage – use ::isWrongCaseUserConfigPage()
+ * ::getSummaryInput() – use ::getSummaryInputWidget()
+ * ::getSummaryInputOOUI() – use ::getSummaryInputWidget()
+ * ::getCheckboxes() – use ::getCheckboxesWidget() or
+ ::getCheckboxesDefinition()
+ * ::getCheckboxesOOUI() – use ::getCheckboxesWidget() or
+ ::getCheckboxesDefinition()
+* ResourceLoaderModule::getPosition(), deprecated in 1.29, has been removed.
+* In User, the cookie-related methods which were wrappers for the functions on
+ the response object, and were deprecated in 1.27, have been removed:
* ::setCookie()
* ::clearCookie()
* ::setExtendedLoginCookie()
Note that User::setCookies() remains, and is not deprecated.
-* Also in User, some auth-related methods which were deprecated in 1.27, have been removed:
- * ::getEditTokenTimestamp() – use MediaWiki\Session\Token::getTimestamp()
- * ::getPasswordFactory() – create a PasswordFactory directly
+* Also in User, some auth-related methods which were deprecated in 1.27 have
+ been removed:
+ * ::getEditTokenTimestamp() – use MediaWiki\Session\Token::getTimestamp()
+ * ::getPasswordFactory() – create a PasswordFactory directly
* ::passwordChangeInputAttribs()
-* The global functions wfProfileIn and wfProfileOut, deprecated in 1.25, have been removed.
+* The global functions wfProfileIn and wfProfileOut, deprecated in 1.25, have
+ been removed.
* SpecialPageFactory::getList(), deprecated in 1.24, has been removed. You can
use ::getNames() instead.
* OpenSearch::getOpenSearchTemplate(), deprecated in 1.25, has been removed. You
can use ApiOpenSearch::getOpenSearchTemplate() instead.
* The global function wfBaseConvert, deprecated in 1.27, has been removed. Use
Wikimedia\base_convert() directly.
-* Calling Database::begin() explicitly during an implicit transaction or when DBO_TRX
- is set results in an exception. Calling Database::commit() explicitly for an implicit
- transaction also results in an exception. Previously these were logged as errors.
- The startAtomic() and endAtomic() methods, or AtomicSectionUpdate should be used
- instead.
+* Calling Database::begin() explicitly during an implicit transaction or when
+ DBO_TRX is set results in an exception. Calling Database::commit() explicitly
+ for an implicit transaction also results in an exception. Previously these
+ were logged as errors. The startAtomic() and endAtomic() methods, or
+ AtomicSectionUpdate should be used instead.
* The global function wfOutputHandler() was removed, use the its replacement
- MediaWiki\OutputHandler::handle() instead. The global function was only sometimes defined.
- Its replacement is always available via the autoloader.
-* ChangeTags::listExtensionActivatedTags and ::listExtensionDefinedTags, deprecated
- in 1.28, have been removed. Use ::listSoftwareActivatedTags() and
+ MediaWiki\OutputHandler::handle() instead. The global function was only
+ sometimes defined. Its replacement is always available via the autoloader.
+* ChangeTags::listExtensionActivatedTags and ::listExtensionDefinedTags,
+ deprecated in 1.28, have been removed. Use ::listSoftwareActivatedTags() and
::listSoftwareDefinedTags() instead.
-* Title::getTitleInvalidRegex(), deprecated in 1.25, has been removed. You
- can use MediaWikiTitleCodec::getTitleInvalidRegex() instead.
+* Title::getTitleInvalidRegex(), deprecated in 1.25, has been removed. You can
+ use MediaWikiTitleCodec::getTitleInvalidRegex() instead.
* HTMLForm & VFormHTMLForm::isVForm(), deprecated in 1.25, have been removed.
* The ProfileSection class, deprecated in 1.25 and unused, has been removed.
-* The ResourceLoaderGetLessVars hook, deprecated in 1.30, has been removed.
- Use ResourceLoaderModule::getLessVars() to expose local variables instead
- of global ones.
-* As part of work to modernise user-generated content clean-up, a config option and some
- methods related to HTML validity were removed without deprecation. The public methods
- MWTidy::checkErrors() and its callee TidyDriverBase::validate() are removed, as are
- MediaWikiTestCase::assertValidHtmlSnippet() and ::assertValidHtmlDocument(). The
- $wgValidateAllHtml configuration option is removed and will be ignored.
-* Execution of external programs using MediaWiki\Shell\Command now applies RESTRICT_DEFAULT
- Firejail restriction by default.
+* The ResourceLoaderGetLessVars hook, deprecated in 1.30, has been removed. Use
+ ResourceLoaderModule::getLessVars() to expose local variables instead of
+ global ones.
+* As part of work to modernise user-generated content clean-up, a config option
+ and some methods related to HTML validity were removed without deprecation.
+ The public methods MWTidy::checkErrors() and the path through which it was
+ called, TidyDriverBase::validate(), are removed, as are the testing methods
+ MediaWikiTestCase::assertValidHtmlSnippet() and ::assertValidHtmlDocument().
+ The $wgValidateAllHtml configuration option is removed and will be ignored.
+* Execution of external programs using MediaWiki\Shell\Command now applies
+ the RESTRICT_DEFAULT Firejail restriction by default.
* The ResourceLoaderModule::getHashMtime() and ::getDefinitionMtime() methods,
deprecated in 1.26, were removed.
+* The deprecated 'mediawiki.widgets.CategorySelector' module alias was removed.
+ Use the 'mediawiki.widgets.CategoryMultiselectWidget' module directly.
=== Deprecations in 1.31 ===
* The Revision class was deprecated in favor of RevisionStore, BlobStore, and
RevisionRecord and its subclasses.
* The global function wfBCP47 is deprecated in favour of LanguageCode::bcp47.
-* The global function wfCountDown is now deprecated in favor of Maintenance::countDown.
+* The global function wfCountDown is now deprecated in favor of
+ Maintenance::countDown.
* Several methods for returning lists of fields to select from the database
have been deprecated in favor of similar methods that also return the tables
to select from and the join conditions for those tables.
* Use of Maintenance::error( $err, $die ) to exit script was deprecated. Use
Maintenance::fatalError() instead.
* Passing a ParserOptions object to OutputPage::parserOptions() is deprecated.
-* The RevisionInsertComplete hook is now deprecated, use RevisionRecordInserted instead.
- RevisionInsertComplete is still called, but the second and third parameter will always be null.
- Hard deprecation is scheduled for 1.32.
+* The RevisionInsertComplete hook is now deprecated; use instead the hook
+ RevisionRecordInserted. RevisionInsertComplete is still called, but the second
+ and third parameter will always be null. Hard deprecation is scheduled for 1.32.
* The following methods that get and set ParserOutput state are deprecated.
Callers should use the new stateless $options parameter to
ParserOutput::getText() instead.
* ParserOutput::setTOCEnabled()
* OutputPage::enableSectionEditLinks()
* OutputPage::sectionEditLinksEnabled()
- * The public ParserOutput state fields $mTOCEnabled and $mEditSectionTokens are also deprecated.
+ * The public ParserOutput state fields $mTOCEnabled and $mEditSectionTokens
+ are also deprecated.
* License::getLicenses has been deprecated; use License::getLines instead.
* QuickTemplate::setRef() was deprecated in favour of QuickTemplate::set().
- Setting template variables by reference allowed violating the principle of data being
- immutable once added to the skin template. In practice, this method was not being
- used for that. Rather, setRef() existed as memory optimisation for PHP 4.
-* QuickTemplate::setTranslator() was deprecated in favour of Skin::msg() parameters.
-* MediaWikiI18N::set() was deprecated in favour of Skin::msg() parameters.
-* MediaWikiI18N::translate() was deprecated in favour of Skin::msg() or wfMessage().
+ Setting template variables by reference allowed violating the principle of
+ data being immutable once added to the skin template. In practice, this method
+ was not being used for that. Rather, setRef() existed as memory optimisation
+ for PHP 4.
+* QuickTemplate::setTranslator() and MediaWikiI18N::set() were deprecated in
+ favour of Skin::msg() parameters.
+* MediaWikiI18N::translate() was deprecated in favour of Skin::msg() or
+ wfMessage().
* Passing false to ParserOptions::setWrapOutputClass() is deprecated. Use the
'unwrap' transform to ParserOutput::getText() instead.
-* \ObjectFactory (no namespace) is deprecated, the namespaced \Wikimedia\ObjectFactory
- from the wikimedia/object-factory library should be used instead.
-* CommentStore::newKey is deprecated. Get an instance from MediaWikiServices instead.
-* The following CommentStore methods have had their signatures changed to introduce a $key parameter,
- usage of the methods on instances retrieved from CommentStore::newKey will remain unchanged but deprecated:
+* \ObjectFactory (no namespace) is deprecated, the namespaced class
+ \Wikimedia\ObjectFactory from the wikimedia/object-factory library should be
+ used instead.
+* CommentStore::newKey is deprecated. Instead, get an instance from
+ MediaWikiServices.
+* The following CommentStore methods have had their signatures changed to
+ introduce a $key parameter, usage of the methods on instances retrieved from
+ CommentStore::newKey will remain unchanged but deprecated:
* CommentStore::getFields
* CommentStore::getJoin
* CommentStore::getComment
* CommentStore::getCommentLegacy
* CommentStore::insert
* CommentStore::insertWithTemplate
-* The following methods in Title have been renamed, and the old ones are deprecated:
- * Title::getSkinFromCssJsSubpage – use ::getSkinFromConfigSubpage
- * Title::isCssOrJsPage – use ::isSiteConfigPage
- * Title::isCssJsSubpage – use ::isUserConfigPage
+* The following methods in Title have been renamed, and the old ones are
+ deprecated:
+ * Title::getSkinFromCssJsSubpage – use ::getSkinFromConfigSubpage
+ * Title::isCssOrJsPage – use ::isSiteConfigPage
+ * Title::isCssJsSubpage – use ::isUserConfigPage
* Title::isCssSubpage – use ::isUserCssConfigPage
* Title::isJsSubpage – use ::isUserJsConfigPage
* The following methods related to caching of half-parsed HTML were deprecated:
used instead.
* The function wfShellWikiCmd() has been deprecated, use
MediaWiki\Shell::makeScriptCommand().
-
=== Other changes in 1.31 ===
* Browser support for Internet Explorer 10 was lowered from Grade A to Grade C.
-* Browser support for Opera 12 and older was removed. Opera 15+ continues at Grade A.
-* Introducing multi-content-revision capability into the storage layer. For details,
- see <https://www.mediawiki.org/wiki/Requests_for_comment/Multi-Content_Revisions>.
-* The "free" CSS class is now only applied to unbracketed URLs in wikitext. Links
- written using square brackets will get the class "text" not "free".
+* Browser support for Opera 12 and older was dropped entirely. Opera 15+
+ continues at Grade A.
+* Multi-content-revision capability was introduced into the storage layer. See
+ <https://mediawiki.org/wiki/Requests_for_comment/Multi-Content_Revisions>.
+* The "free" CSS class is now only applied to unbracketed URLs in wikitext.
+ Links written using square brackets will get the class "text" not "free".
* RFC 157418: Whitespace is trimmed from wikitext headings, wikitext list items,
wikitext table captions, wikitext table headings, wikitext table cells. HTML
- headings, HTML list items, HTML table captions, HTML table headings, HTML table cells
- will not have this trimming behavior.
+ headings, HTML list items, HTML table captions, HTML table headings, HTML
+ table cells will not have this trimming behavior.
== Compatibility ==
-MediaWiki 1.31 requires PHP 5.5.9 or later. Although HHVM 3.18.5 or later is supported,
-it is generally advised to use PHP 5.5.9 or later for long term support.
+MediaWiki 1.31 requires PHP 7.0.0 or later. Although HHVM 3.18.5 or later is
+supported, it is generally advised to use PHP 7.0.0 or later for long term
+support.
MySQL/MariaDB is the recommended DBMS. PostgreSQL or SQLite can also be used,
but support for them is somewhat less mature. There is experimental support for
* The $wgSiteSupportPage setting, unused since 1.5, was removed.
* $wgJpegQuality was added to allow configuring the quality of JPEG thumbnails (default 80).
* The default quality of JPEG thumbnails generated by GD was reduced from 95 to 80.
+* $wgExperimentalHtmlIds, deprecated since 1.30, has been removed. The 'html5-legacy' value for
+ $wgFragmentMode is no longer accepted.
* …
=== New features in 1.32 ===
* …
==== Upgraded external libraries ====
-* …
+* Updated QUnit from 2.4.0 to 2.6.0.
==== New external libraries ====
* …
regularly. Below only new and removed languages are listed, as well as
changes to languages because of Phabricator reports.
-* …
+* (T193566) Added language support for Ambonese Malay (abs).
=== Breaking changes in 1.32 ===
* $wgRequestTime was removed (deprecated in 1.25).
removed (deprecated in 1.31).
* The EDIT_TOKEN_SUFFIX constant was removed (deprecated in 1.27).
Use MediaWiki\Session\Token::SUFFIX instead.
-* EditPage::isOouiEnabled(), deprecated in 1.30, was removed.
+* EditPage::isOouiEnabled() was removed (deprecated in 1.30).
+* mw.util.wikiGetlink() was removed (deprecated in 1.23).
+ Use mw.util.getUrl() instead.
+* (T61113) The following methods and constants from the Revision class were deprecated in
+ 1.25 and have now been removed.
+ * Revision::getRawUser()
+ * Revision::getRawUserText()
+ * Revision::getRawComment()
+* window.gM() from mediawiki.jqueryMsg was removed (deprecated in 1.23).
+ Use mw.msg() or mw.message() instead.
+* The SqlDataUpdate class, deprecated in 1.28, has been removed.
=== Deprecations in 1.32 ===
* Use of a StartProfiler.php file is deprecated in favour of placing
configuration in LocalSettings.php.
* HTMLForm::setSubmitProgressive() is deprecated. No need to call it. Submit
button is already marked as progressive.
+* Skin::setupSkinUserCss() is deprecated. Adding of modules to load
+ has been centralised to Skin::getDefaultModules(), which is now capable
+ of queueing style modules as well.
+* OutputPage::addModuleScripts() and ParserOutput::addModuleScripts are deprecated.
+ Use addModules() instead.
=== Other changes in 1.32 ===
* …
'BenchmarkSanitizer' => __DIR__ . '/maintenance/benchmarks/benchmarkSanitizer.php',
'BenchmarkTidy' => __DIR__ . '/maintenance/benchmarks/benchmarkTidy.php',
'Benchmarker' => __DIR__ . '/maintenance/benchmarks/Benchmarker.php',
- 'BitmapHandler' => __DIR__ . '/includes/media/Bitmap.php',
- 'BitmapHandler_ClientOnly' => __DIR__ . '/includes/media/Bitmap_ClientOnly.php',
+ 'BitmapHandler' => __DIR__ . '/includes/media/BitmapHandler.php',
+ 'BitmapHandler_ClientOnly' => __DIR__ . '/includes/media/BitmapHandler_ClientOnly.php',
'BitmapMetadataHandler' => __DIR__ . '/includes/media/BitmapMetadataHandler.php',
'Blob' => __DIR__ . '/includes/libs/rdbms/encasing/Blob.php',
'Block' => __DIR__ . '/includes/Block.php',
'BlockLevelPass' => __DIR__ . '/includes/parser/BlockLevelPass.php',
'BlockListPager' => __DIR__ . '/includes/specials/pagers/BlockListPager.php',
'BlockLogFormatter' => __DIR__ . '/includes/logging/BlockLogFormatter.php',
- 'BmpHandler' => __DIR__ . '/includes/media/BMP.php',
+ 'BmpHandler' => __DIR__ . '/includes/media/BmpHandler.php',
'BotPassword' => __DIR__ . '/includes/user/BotPassword.php',
'BrokenRedirectsPage' => __DIR__ . '/includes/specials/SpecialBrokenRedirects.php',
'BufferingStatsdDataFactory' => __DIR__ . '/includes/libs/stats/BufferingStatsdDataFactory.php',
'DiffOpDelete' => __DIR__ . '/includes/diff/DairikiDiff.php',
'DifferenceEngine' => __DIR__ . '/includes/diff/DifferenceEngine.php',
'Digit2Html' => __DIR__ . '/maintenance/language/digit2html.php',
- 'DjVuHandler' => __DIR__ . '/includes/media/DjVu.php',
+ 'DjVuHandler' => __DIR__ . '/includes/media/DjVuHandler.php',
'DjVuImage' => __DIR__ . '/includes/media/DjVuImage.php',
'DnsSrvDiscoverer' => __DIR__ . '/includes/libs/DnsSrvDiscoverer.php',
'DoubleRedirectJob' => __DIR__ . '/includes/jobqueue/jobs/DoubleRedirectJob.php',
'EventRelayerNull' => __DIR__ . '/includes/libs/eventrelayer/EventRelayerNull.php',
'ExecutableFinder' => __DIR__ . '/includes/utils/ExecutableFinder.php',
'Exif' => __DIR__ . '/includes/media/Exif.php',
- 'ExifBitmapHandler' => __DIR__ . '/includes/media/ExifBitmap.php',
+ 'ExifBitmapHandler' => __DIR__ . '/includes/media/ExifBitmapHandler.php',
'ExplodeIterator' => __DIR__ . '/includes/libs/ExplodeIterator.php',
'ExportProgressFilter' => __DIR__ . '/includes/export/ExportProgressFilter.php',
'ExportSites' => __DIR__ . '/maintenance/exportSites.php',
'FormatMetadata' => __DIR__ . '/includes/media/FormatMetadata.php',
'FormattedRCFeed' => __DIR__ . '/includes/rcfeed/FormattedRCFeed.php',
'FormlessAction' => __DIR__ . '/includes/actions/FormlessAction.php',
- 'GIFHandler' => __DIR__ . '/includes/media/GIF.php',
+ 'GIFHandler' => __DIR__ . '/includes/media/GIFHandler.php',
'GIFMetadataExtractor' => __DIR__ . '/includes/media/GIFMetadataExtractor.php',
'GanConverter' => __DIR__ . '/languages/classes/LanguageGan.php',
'GenderCache' => __DIR__ . '/includes/cache/GenderCache.php',
'JobQueueSecondTestQueue' => __DIR__ . '/includes/jobqueue/JobQueueSecondTestQueue.php',
'JobRunner' => __DIR__ . '/includes/jobqueue/JobRunner.php',
'JobSpecification' => __DIR__ . '/includes/jobqueue/JobSpecification.php',
- 'JpegHandler' => __DIR__ . '/includes/media/Jpeg.php',
+ 'JpegHandler' => __DIR__ . '/includes/media/JpegHandler.php',
'JpegMetadataExtractor' => __DIR__ . '/includes/media/JpegMetadataExtractor.php',
'JsonContent' => __DIR__ . '/includes/content/JsonContent.php',
'JsonContentHandler' => __DIR__ . '/includes/content/JsonContentHandler.php',
'Orphans' => __DIR__ . '/maintenance/orphans.php',
'OutputPage' => __DIR__ . '/includes/OutputPage.php',
'PHPVersionCheck' => __DIR__ . '/includes/PHPVersionCheck.php',
- 'PNGHandler' => __DIR__ . '/includes/media/PNG.php',
+ 'PNGHandler' => __DIR__ . '/includes/media/PNGHandler.php',
'PNGMetadataExtractor' => __DIR__ . '/includes/media/PNGMetadataExtractor.php',
'PPCustomFrame_DOM' => __DIR__ . '/includes/parser/Preprocessor_DOM.php',
'PPCustomFrame_Hash' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
'SpecialWatchlist' => __DIR__ . '/includes/specials/SpecialWatchlist.php',
'SpecialWhatLinksHere' => __DIR__ . '/includes/specials/SpecialWhatlinkshere.php',
'SqlBagOStuff' => __DIR__ . '/includes/objectcache/SqlBagOStuff.php',
- 'SqlDataUpdate' => __DIR__ . '/includes/deferred/SqlDataUpdate.php',
'SqlSearchResultSet' => __DIR__ . '/includes/search/SqlSearchResultSet.php',
'Sqlite' => __DIR__ . '/maintenance/sqlite.inc',
'SqliteInstaller' => __DIR__ . '/includes/installer/SqliteInstaller.php',
'StubUserLang' => __DIR__ . '/includes/StubObject.php',
'SubmitAction' => __DIR__ . '/includes/actions/SubmitAction.php',
'SubpageImportTitleFactory' => __DIR__ . '/includes/title/SubpageImportTitleFactory.php',
- 'SvgHandler' => __DIR__ . '/includes/media/SVG.php',
+ 'SvgHandler' => __DIR__ . '/includes/media/SvgHandler.php',
'SwiftFileBackend' => __DIR__ . '/includes/libs/filebackend/SwiftFileBackend.php',
'SwiftFileBackendDirList' => __DIR__ . '/includes/libs/filebackend/SwiftFileBackend.php',
'SwiftFileBackendFileList' => __DIR__ . '/includes/libs/filebackend/SwiftFileBackend.php',
'ThumbnailImage' => __DIR__ . '/includes/media/MediaTransformOutput.php',
'ThumbnailRenderJob' => __DIR__ . '/includes/jobqueue/jobs/ThumbnailRenderJob.php',
'TidyUpBug37714' => __DIR__ . '/maintenance/tidyUpBug37714.php',
- 'TiffHandler' => __DIR__ . '/includes/media/Tiff.php',
+ 'TiffHandler' => __DIR__ . '/includes/media/TiffHandler.php',
'Timing' => __DIR__ . '/includes/libs/Timing.php',
'Title' => __DIR__ . '/includes/Title.php',
'TitleArray' => __DIR__ . '/includes/TitleArray.php',
'WebInstallerUpgrade' => __DIR__ . '/includes/installer/WebInstallerUpgrade.php',
'WebInstallerUpgradeDoc' => __DIR__ . '/includes/installer/WebInstallerUpgradeDoc.php',
'WebInstallerWelcome' => __DIR__ . '/includes/installer/WebInstallerWelcome.php',
- 'WebPHandler' => __DIR__ . '/includes/media/WebP.php',
+ 'WebPHandler' => __DIR__ . '/includes/media/WebPHandler.php',
'WebRequest' => __DIR__ . '/includes/WebRequest.php',
'WebRequestUpload' => __DIR__ . '/includes/WebRequestUpload.php',
'WebResponse' => __DIR__ . '/includes/WebResponse.php',
"wikimedia/cdb": "1.4.1",
"wikimedia/cldr-plural-rule-parser": "1.0.0",
"wikimedia/composer-merge-plugin": "1.4.1",
- "wikimedia/html-formatter": "1.0.1",
+ "wikimedia/html-formatter": "1.0.2",
"wikimedia/ip-set": "1.2.0",
"wikimedia/object-factory": "1.0.0",
"wikimedia/php-session-serializer": "1.0.6",
It's often the case that the best algorithm to use for a given task
depends on whether or not replication is in use. Due to our unabashed
Wikipedia-centrism, we often just use the replication-friendly version,
-but if you like, you can use wfGetLB()->getServerCount() > 1 to
+but if you like, you can use LoadBalancer::getServerCount() > 1 to
check to see if replication is in use.
=== Lag ===
slave to catch up to that position before doing any reads from it. If
this wait times out, reads are allowed anyway, but the request is
considered to be in "lagged slave mode". Lagged slave mode can be
-checked by calling wfGetLB()->getLaggedReplicaMode(). The only
+checked by calling LoadBalancer::getLaggedReplicaMode(). The only
practical consequence at present is a warning displayed in the page
footer.
/**
* Compat method allowing use of self::newKey until removed.
* @param string|null $methodKey
- * @throw InvalidArgumentException
+ * @throws InvalidArgumentException
* @return string
*/
private function getKey( $methodKey = null ) {
* $wgSharedSchema is the table schema for the shared database. It defaults to
* $wgDBmwschema.
*
- * @deprecated since 1.21 In new code, use the $wiki parameter to wfGetLB() to
- * access remote databases. Using wfGetLB() allows the shared database to
+ * @deprecated since 1.21 In new code, use the $wiki parameter to LBFactory::getMainLB() to
+ * access remote databases. Using LBFactory::getMainLB() allows the shared database to
* reside on separate servers to the wiki's own database, with suitable
* configuration of $wgLBFactoryConf.
*/
*/
$wgDisableOutputCompression = false;
-/**
- * Abandoned experiment with HTML5-style ID escaping. Normalized IDs a bit
- * too aggressively, breaking preexisting content (particularly Cite).
- * See T29733, T29694, T29474.
- *
- * @deprecated since 1.30, use $wgFragmentMode
- */
-$wgExperimentalHtmlIds = false;
-
/**
* How should section IDs be encoded?
* This array can contain 1 or 2 elements, each of them can be one of:
* - 'html5' is modern HTML5 style encoding with minimal escaping. Displays Unicode
* characters in most browsers' address bars.
* - 'legacy' is old MediaWiki-style encoding, e.g. 啤酒 turns into .E5.95.A4.E9.85.92
- * - 'html5-legacy' corresponds to DEPRECATED $wgExperimentalHtmlIds mode. DO NOT use
- * it for anything but migration off that mode (see below).
*
* The first element of this array specifies the primary mode of escaping IDs. This
* is what users will see when they e.g. follow an [[#internal link]] to a section of
*
* @todo Need to integrate this into wfExpandUrl (see T34168)
*
+ * @since 1.19
+ *
* @param string $urlPath URL path, potentially containing dot-segments
* @return string URL path with all dot-segments removed
*/
* @param LoggerInterface $runJobsLogger
*/
private function triggerSyncJobs( $n, LoggerInterface $runJobsLogger ) {
- $runner = new JobRunner( $runJobsLogger );
- $runner->run( [ 'maxJobs' => $n ] );
+ $trxProfiler = Profiler::instance()->getTransactionProfiler();
+ $old = $trxProfiler->setSilenced( true );
+ try {
+ $runner = new JobRunner( $runJobsLogger );
+ $runner->run( [ 'maxJobs' => $n ] );
+ } finally {
+ $trxProfiler->setSilenced( $old );
+ }
}
/**
}
/**
- * Add one or more modules recognized by ResourceLoader. Modules added
- * through this function will be loaded by ResourceLoader when the
- * page loads.
+ * Load one or more ResourceLoader modules on this page.
*
* @param string|array $modules Module name (string) or array of module names
*/
}
/**
- * Get the list of module JS to include on this page
+ * Get the list of script-only modules to load on this page.
*
* @param bool $filter
* @param string|null $position Unused
}
/**
- * Add only JS of one or more modules recognized by ResourceLoader. Module
- * scripts added through this function will be loaded by ResourceLoader when
- * the page loads.
+ * Load the scripts of one or more ResourceLoader modules, on this page.
*
+ * This method exists purely to provide the legacy behaviour of loading
+ * a module's scripts in the global scope, and without dependency resolution.
+ * See <https://phabricator.wikimedia.org/T188689>.
+ *
+ * @deprecated since 1.31 Use addModules() instead.
* @param string|array $modules Module name (string) or array of module names
*/
public function addModuleScripts( $modules ) {
}
/**
- * Get the list of module CSS to include on this page
+ * Get the list of style-only modules to load on this page.
*
* @param bool $filter
* @param string|null $position Unused
}
/**
- * Add only CSS of one or more modules recognized by ResourceLoader.
+ * Load the styles of one or more ResourceLoader modules on this page.
*
- * Module styles added through this function will be added using standard link CSS
- * tags, rather than as a combined Javascript and CSS package. Thus, they will
- * load when JavaScript is disabled (unless CSS also happens to be disabled).
+ * Module styles added through this function will be loaded as a stylesheet,
+ * using a standard `<link rel=stylesheet>` HTML tag, rather than as a combined
+ * Javascript and CSS package. Thus, they will even load when JavaScript is disabled.
*
* @param string|array $modules Module name (string) or array of module names
*/
return $user ? $user->getId() : 0;
}
- /**
- * Fetch revision's user id without regard for the current user's permissions
- *
- * @return int
- * @deprecated since 1.25, use getUser( Revision::RAW )
- */
- public function getRawUser() {
- wfDeprecated( __METHOD__, '1.25' );
- return $this->getUser( self::RAW );
- }
-
/**
* Fetch revision's username if it's available to the specified audience.
* If the specified audience does not have access to the username, an
$user = $this->mRecord->getUser( $audience, $user );
return $user ? $user->getName() : '';
}
-
- /**
- * Fetch revision's username without regard for view restrictions
- *
- * @return string
- * @deprecated since 1.25, use getUserText( Revision::RAW )
- */
- public function getRawUserText() {
- wfDeprecated( __METHOD__, '1.25' );
- return $this->getUserText( self::RAW );
- }
-
/**
* Fetch revision comment if it's available to the specified audience.
* If the specified audience does not have access to the comment, an
return $comment === null ? null : $comment->text;
}
- /**
- * Fetch revision comment without regard for the current user's permissions
- *
- * @return string
- * @deprecated since 1.25, use getComment( Revision::RAW )
- */
- public function getRawComment() {
- wfDeprecated( __METHOD__, '1.25' );
- return $this->getComment( self::RAW );
- }
-
/**
* @return bool
*/
}
unset( $repo ); // no global pollution; destroy reference
-// Convert this deprecated setting to modern system
-if ( $wgExperimentalHtmlIds ) {
- wfDeprecated( '$wgExperimentalHtmlIds', '1.30' );
- $wgFragmentMode = [ 'html5-legacy', 'html5' ];
-}
-
$rcMaxAgeDays = $wgRCMaxAge / ( 3600 * 24 );
if ( $wgRCFilterByAge ) {
// Trim down $wgRCLinkDays so that it only lists links which are valid
* @param mixed $value
* @param string $name
*
- * @throw IncompleteRevisionException if $value is null
+ * @throws IncompleteRevisionException if $value is null
* @return mixed $value, if $value is not null
*/
private function failOnNull( $value, $name ) {
* @param mixed $value
* @param string $name
*
- * @throw IncompleteRevisionException if $value is empty
+ * @throws IncompleteRevisionException if $value is empty
* @return mixed $value, if $value is not null
*/
private function failOnEmpty( $value, $name ) {
* @param string|null $blobFormat MIME type indicating how $dataBlob is encoded
* @param int $queryFlags
*
- * @throw RevisionAccessException
+ * @throws RevisionAccessException
* @return Content
*/
private function loadSlotContent(
* @param string $blobAddress
* @param int $queryFlags
*
- * @throw BlobAccessException
+ * @throws BlobAccessException
* @return string|false
*/
private function fetchBlob( $blobAddress, $queryFlags ) {
"apihelp-edit-param-tags": "Cambia las etiquetas para aplicarlas a la revisión.",
"apihelp-edit-param-minor": "Edición menor.",
"apihelp-edit-param-notminor": "Edición no menor.",
- "apihelp-edit-param-bot": "Marcar esta edición como edición de bot.",
+ "apihelp-edit-param-bot": "Marcar esta como una edición de robot.",
"apihelp-edit-param-basetimestamp": "Marca de tiempo de la revisión base, usada para detectar conflictos de edición. Se puede obtener mediante [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]]",
"apihelp-edit-param-starttimestamp": "Marca de tiempo de cuando empezó el proceso de edición, usada para detectar conflictos de edición. Se puede obtener un valor apropiado usando <var>[[Special:ApiHelp/main|curtimestamp]]</var> cuando comiences el proceso de edición (por ejemplo, al cargar el contenido de la página por editar).",
"apihelp-edit-param-recreate": "Reemplazar los errores acerca de la página de haber sido eliminados en el ínterin.",
"Umherirrender"
]
},
- "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|ת×\99×¢×\95×\93]]\n* [[mw:Special:MyLanguage/API:FAQ|ש×\95\"ת]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api רש×\99×\9eת ×\93×\99×\95×\95ר]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce ×\94×\95×\93×¢×\95ת ×¢×\9c API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R ×\91×\90×\92×\99×\9d ×\95×\91קש×\95ת]\n</div>\n<strong>×\9eצ×\91:</strong> ×\9b×\9c ×\94×\90פשר×\95×\99×\95ת ש×\9e×\95צ×\92×\95ת ×\91×\93×£ ×\94×\96×\94 ×\90×\9e×\95ר×\95ת ×\9c×¢×\91×\95×\93, ×\90×\91×\9c ×\94Ö¾API ×¢×\93×\99×\99×\9f ×\91פ×\99ת×\95×\97 פע×\99×\9c, ×\95×\99×\9b×\95×\9c ×\9c×\94×©×ª× ×\95ת ×\91×\9b×\9c ×\96×\9e×\9f. עש×\95 ×\9e×\99× ×\95×\99 ×\9c[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ רש×\99×\9eת ×\94×\93×\99×\95×\95ר mediawiki-api-announce] ×\9c×\94×\95×\93×¢×\95ת ×¢×\9c ×¢×\93×\9b×\95× ×\99×\9d.\n\n<strong>×\91קש×\95ת ש×\92×\95×\99×\95ת:</strong> ×\9bש×\91קש×\95ת ש×\92×\95×\99×\95ת × ×©×\9c×\97×\95ת ×\9cÖ¾API, ת×\99ש×\9c×\97 ×\9b×\95תרת HTTP ×¢×\9d ×\94×\9eפת×\97 \"MediaWiki-API-Error\" ×\95×\90×\96 ×\92×\9d ×\94ער×\9a ש×\9c ×\94×\9b×\95תרת ×\95×\92×\9d ק×\95×\93 ×\94ש×\92×\99×\90×\94 ×\99×\95×\92×\93ר×\95 ×\9c×\90×\95ת×\95 ער×\9a. ×\9c×\9e×\99×\93×¢ × ×\95סף ר' [[mw:Special:MyLanguage/API:Errors_and_warnings|API: ש×\92×\99×\90×\95ת ×\95×\90×\96×\94ר×\95ת]].\n\n<strong>×\91×\93×\99ק×\94:</strong> ×\9c×\91×\93×\99ק×\94 ק×\9c×\94 ×\99×\95תר ש×\9c ×\91קש×\95ת ר' [[Special:ApiSandbox]].",
+ "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|ת×\99×¢×\95×\93]]\n* [[mw:Special:MyLanguage/API:FAQ|ש×\90×\9c×\95ת × ×¤×\95צ×\95ת]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api רש×\99×\9eת ×\93×\99×\95×\95ר]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce ×\94×\95×\93×¢×\95ת ×¢×\9c API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R ×\91×\90×\92×\99×\9d ×\95×\91קש×\95ת]\n</div>\n<strong>×\9eצ×\91:</strong> ×\94Ö¾API ש×\9c ×\9e×\93×\99×\94Ö¾×\95×\99ק×\99 ×\94×\95×\90 ×\9e×\9eשק ×\95ת×\99ק ×\95×\99צ×\99×\91 ×©× ×ª×\9e×\9a ×\95×\9eשתפר ×\91×\90×\95פ×\9f ס×\93×\99ר. ×\9c×\9eר×\95ת ש×\90× ×\97× ×\95 ×\9eשת×\93×\9c×\99×\9d ×\9c×\94×\99×\9e× ×¢ ×\9e×\9b×\9a, ×\9cעת×\99×\9d ×¢×\9c×\99× ×\95 ×\9c×\91צע ש×\99× ×\95×\99×\99×\9d שע×\9c×\95×\9c×\99×\9d ×\9cש×\91ש ×\93×\91ר×\99×\9d ×\91פ×\95× ×§×¦×\99×\95× ×\9c×\99×\95ת ×\94×\96×\95; ×\91×\90פשר×\95ת×\9a ×\9cעש×\95ת ×\9e×\99× ×\95×\99 ×\9c[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ רש×\99×\9eת ×\94×\93×\99×\95×\95ר mediawiki-api-announce] ×\9b×\93×\99 ×\9cק×\91×\9c ×\94×\95×\93×¢×\95ת ×¢×\9c ×¢×\93×\9b×\95× ×\99×\9d.\n\n<strong>×\91קש×\95ת ש×\92×\95×\99×\95ת:</strong> ×\9bש×\91קש×\95ת ש×\92×\95×\99×\95ת × ×©×\9c×\97×\95ת ×\9cÖ¾API, ת×\99ש×\9c×\97 ×\9b×\95תרת HTTP ×¢×\9d ×\94×\9eפת×\97 \"MediaWiki-API-Error\", ×\95×\90×\96 ×\92×\9d ×\94ער×\9a ש×\9c ×\94×\9b×\95תרת ×\95×\92×\9d ק×\95×\93 ×\94ש×\92×\99×\90×\94 ×\99×\95×\92×\93ר×\95 ×\9c×\90×\95ת×\95 ער×\9a. ×\9c×\9e×\99×\93×¢ × ×\95סף, ×\90פשר ×\9c×¢×\99×\99×\9f ×\91×\93×£ [[mw:Special:MyLanguage/API:Errors_and_warnings|API: ש×\92×\99×\90×\95ת ×\95×\90×\96×\94ר×\95ת]].\n\n<p class=\"mw-apisandbox-link\"><strong>×\91×\93×\99ק×\94:</strong> ×\9c×\91×\93×\99ק×\94 ק×\9c×\94 ×\99×\95תר ש×\9c ×\91קש×\95ת, ×\90פשר ×\9c×\94שת×\9eש ×\91[[Special:ApiSandbox|×\90ר×\92×\96 ×\94×\97×\95×\9c ש×\9c API]].</p>",
"apihelp-main-param-action": "איזו פעולה לבצע.",
"apihelp-main-param-format": "תסדיר הפלט.",
"apihelp-main-param-maxlag": "שיהוי מרבי יכול לשמש כשמדיה־ויקי מותקנת בצביר עם מסד נתונים משוכפל. כדי לחסוך בפעולות שגורמות יותר שיהוי בשכפול אתר, הפרמטר הזה יכול לגרום ללקוח להמתין עד ששיהוי השכפול יורד מתחת לערך שצוין. במקרה של שיהוי מוגזם, קוד השגיאה <samp>maxlag</samp> מוחזר עם הודעה כמו <samp>Waiting for $host: $lag seconds lagged</samp>.<br />ר' [[mw:Special:MyLanguage/Manual:Maxlag_parameter|מדריך למשתמש: פרמטר maxlag]] למידע נוסף.",
"apihelp-compare-param-fromid": "מס׳ זיהוי של הדף הראשון להשוואה.",
"apihelp-compare-param-fromrev": "גרסה ראשונה להשוואה.",
"apihelp-compare-param-fromtext": "להשתמש בטקסט הזה במקום תוכן הגרסה שהוגדרה על־ידי <var dir=\"ltr\">fromtitle</var>, <var dir=\"ltr\">fromid</var> או <var dir=\"ltr\">fromrev</var>.",
+ "apihelp-compare-param-fromsection": "יש להשתמש רק בפסקה שצוינה בתוכן של הפרמטר 'from'.",
"apihelp-compare-param-frompst": "לעשות התמרה לפני שמירה ב־<var>fromtext</var>.",
"apihelp-compare-param-fromcontentmodel": "מודל התוכן של <var>fromtext</var>. אם זה לא סופק, ייעשה ניחוש על סמך פרמטרים אחרים.",
"apihelp-compare-param-fromcontentformat": "תסדיר הסדרת תוכן של <var>fromtext</var>.",
"apihelp-compare-param-torev": "גרסה שנייה להשוואה.",
"apihelp-compare-param-torelative": "להשתמש בגרסה יחסית לגרסה שהוסקה מ<var dir=\"ltr\">fromtitle</var>, <var dir=\"ltr\">fromid</var> או <var dir=\"ltr\">fromrev</var>. לכל אפשריות ה־\"to\" האחרות לא תהיה השפעה.",
"apihelp-compare-param-totext": "להשתמש בטקסט הזה במקום התוכן של הגרסה שהוגדר ב־<var dir=\"ltr\">totitle</var>, <var dir=\"ltr\">toid</var> or <var dir=\"ltr\">torev</var>.",
+ "apihelp-compare-param-tosection": "יש להשתמש רק בפסקה שצוינה בתוכן של הפרמטר 'to'.",
"apihelp-compare-param-topst": "לעשות התמרה לפני שמירה ב־<var>totext</var>.",
"apihelp-compare-param-tocontentmodel": "מודל התוכן של <var>totext</var>. אם זה לא סופק, ייעשה ניחוש על סמך פרמטרים אחרים.",
"apihelp-compare-param-tocontentformat": "תסדיר הסדרת תוכן של <var>fromtext</var>.",
"apihelp-import-extended-description": "יש לשים לב לכך שפעולת HTTP POST צריכה להיעשות בתור העלאת קובץ (כלומר, עם multipart/form-data) בזמן שליחת קובץ לפרמטר <var>xml</var>.",
"apihelp-import-param-summary": "תקציר ייבוא עיולי יומן.",
"apihelp-import-param-xml": "קובץ XML שהועלה.",
+ "apihelp-import-param-interwikiprefix": "לייבוא באמצעות העלאת קבצים: תחילית הבינוויקי שתוצג עבור שמות משתמשים שאינם מוכרים (וגם עבור שמות משתמשים מוכרים אם <var>$1assignknownusers</var> מוגדר).",
+ "apihelp-import-param-assignknownusers": "הקצאת העריכות למשתמשים המקומיים כאשר משתמשים בשמות זהים קיימים באתר המקומי.",
"apihelp-import-param-interwikisource": "ליבוא בין אתרי ויקי: מאיזה ויקי לייבא.",
"apihelp-import-param-interwikipage": "ליבוא בין אתרי ויקי: איזה דף לייבא.",
"apihelp-import-param-fullhistory": "ליבוא בין אתרי ויקי: לייבר את ההיסטוריה המלאה, לא רק את הגרסה הנוכחית.",
"apihelp-opensearch-summary": "חיפוש בוויקי בפרוטוקול OpenSearch.",
"apihelp-opensearch-param-search": "מחרוזת לחיפוש.",
"apihelp-opensearch-param-limit": "המספר המרבי של התוצאות שתוחזרנה.",
- "apihelp-opensearch-param-namespace": "ש×\9e×\95ת ×\9eת×\97×\9d ×\9c×\97×\99פ×\95ש.",
+ "apihelp-opensearch-param-namespace": "×\9eר×\97×\91×\99 ×\94ש×\9d ש×\91×\94×\9d ×\99ת×\91צע ×\94×\97×\99פ×\95ש. ×\9cש×\93×\94 ×\96×\94 ×\90×\99×\9f ×\9eש×\9e×¢×\95ת ×\90×\9d <var>$1search</var> ×\9eת×\97×\99×\9c ×¢×\9d ת×\97×\99×\9c×\99ת תק×\99× ×\94 ש×\9c ×\9eר×\97×\91 ש×\9d.",
"apihelp-opensearch-param-suggest": "לא לעשות דבר אם <var>[[mw:Special:MyLanguage/Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> הוא false.",
"apihelp-opensearch-param-redirects": "איך לטפל בהפניות:\n;return:להחזיר את ההפניה עצמה.\n;resolve:להחזיר את דף היעד. יכול להחזיר פחות מ־$1limit תוצאות.\nמסיבות היסטוריות, בררת המחדל היא \"return\" עבור $1format=json ו־\"resolve\" עבור תסדירים אחרים.",
"apihelp-opensearch-param-format": "תסדיר הפלט.",
"apihelp-parse-param-disablepp": "יש להשתמש ב־<var>$1disablelimitreport</var> במקום.",
"apihelp-parse-param-disableeditsection": "להשמיט את קישורי עריכת הפסקאות מפלט המפענח.",
"apihelp-parse-param-disabletidy": "לא להריץ ניקוי HTML (למשל tidy) על פלט המפענח.",
+ "apihelp-parse-param-disablestylededuplication": "לא להסיר סגנונות כפולים בפלט של המפענח.",
"apihelp-parse-param-generatexml": "יצירת עץ פענוח של XML (נדרש מודל תוכן <code>$1</code>; מוחלף ב־<kbd>$2prop=parsetree</kbd>).",
"apihelp-parse-param-preview": "לפענח במצב תצוגה מקדימה.",
"apihelp-parse-param-sectionpreview": "לפענח במצב תצוגה מקדימה של פסקה (מדליק גם את מצב תצוגה מקדימה).",
"apihelp-query+prefixsearch-summary": "ביצוע חיפוש תחילית של כותרות דפים.",
"apihelp-query+prefixsearch-extended-description": "למרות הדמיון בשם, המודול הזה אינו אמור להיות שווה ל־[[Special:PrefixIndex]] (\"מיוחד:דפים המתחילים ב\"); לדבר כזה, ר' <kbd>[[Special:ApiHelp/query+allpages|action=query&list=allpages]]</kbd> עם הפרמטר <kbd>apprefix</kbd>. מטרת המודול הזה דומה ל־<kbd>[[Special:ApiHelp/opensearch|action=opensearch]]</kbd>: לקבל קלט ממשתמש ולספק את הכותרות המתאימות ביותר. בהתאם לשרת מנוע החיפוש, זה יכול לכלול תיקון שגיאות כתיב, הימנעות מדפי הפניה והירסטיקות אחרות.",
"apihelp-query+prefixsearch-param-search": "מחרוזת לחיפוש.",
- "apihelp-query+prefixsearch-param-namespace": "ש×\9e×\95ת ×\9eת×\97×\9d ×\9c×\97×\99פ×\95ש.",
+ "apihelp-query+prefixsearch-param-namespace": "×\9eר×\97×\91×\99 ×\94ש×\9d ש×\91×\94×\9d ×\99ת×\91צע ×\94×\97×\99פ×\95ש. ×\9cש×\93×\94 ×\96×\94 ×\90×\99×\9f ×\9eש×\9e×¢×\95ת ×\90×\9d <var>$1search</var> ×\9eת×\97×\99×\9c ×¢×\9d ת×\97×\99×\9c×\99ת תק×\99× ×\94 ש×\9c ×\9eר×\97×\91 ש×\9d.",
"apihelp-query+prefixsearch-param-limit": "מספר התוצאות המרבי להחזרה.",
"apihelp-query+prefixsearch-param-offset": "מספר תוצאות לדילוג.",
"apihelp-query+prefixsearch-example-simple": "חיפוש שםות דפים שמתחילים ב־<kbd>meaning</kbd>.",
"apihelp-query+search-paramvalue-prop-sectiontitle": "הוספת שם הפסקה התואמת.",
"apihelp-query+search-paramvalue-prop-categorysnippet": "הוספת קטע קצר מפוענח של הקטגוריה התואמת.",
"apihelp-query+search-paramvalue-prop-isfilematch": "הוספת בוליאני שמציין אם החיפוש תאם לתוכן של קובץ.",
+ "apihelp-query+search-paramvalue-prop-extensiondata": "הוספת נתונים נוספים שנוצרים על־ידי הרחבות.",
"apihelp-query+search-paramvalue-prop-score": "חסר־השפעה.",
"apihelp-query+search-paramvalue-prop-hasrelated": "חסר־השפעה.",
"apihelp-query+search-param-limit": "כמה דפים להחזיר בסך הכול.",
"apihelp-query+watchlist-paramvalue-prop-parsedcomment": "הוספת ההערכה המפוענחת של העריכה.",
"apihelp-query+watchlist-paramvalue-prop-timestamp": "הוספת חותם־זמן של העריכה.",
"apihelp-query+watchlist-paramvalue-prop-patrol": "תיוג עריכות שנבדקו.",
+ "apihelp-query+watchlist-paramvalue-prop-autopatrol": "תיוג עריכות המסומנות כבדוקות באופן אוטומטי.",
"apihelp-query+watchlist-paramvalue-prop-sizes": "הוספת האורך החדש והישן של הדף.",
"apihelp-query+watchlist-paramvalue-prop-notificationtimestamp": "הוספת חותם־זמן של ההודעה האחרונה למשתמש על העריכה.",
"apihelp-query+watchlist-paramvalue-prop-loginfo": "הוספת מידע מהיומן איפה שמתאים.",
+ "apihelp-query+watchlist-paramvalue-prop-tags": "רשימת תגיות עבור הפעולה.",
"apihelp-query+watchlist-param-show": "הצגה רק של פריטים שמתאימים לאמות המידה האלו. למשל, כדי לראות רק עריכות משניות שעשו משתמשים שנכנסו לחשבון, יש להגדיר $1show=minor|!anon.",
"apihelp-query+watchlist-param-type": "אולי סוגי שינויים להציג:",
"apihelp-query+watchlist-paramvalue-type-edit": "עריכות דף רגילות.",
"apierror-chunk-too-small": "גודל הפלח המזערי הוא {{PLURAL:$1|בית אחד|$1 בתים}} בשביל פלחים לא סופיים.",
"apierror-cidrtoobroad": "טווחי CIDR של $1 שרחבים יותר מ־/$2 אינם קבילים.",
"apierror-compare-no-title": "לא ניתן לעשות התמרה לפני שמירה ללא כותרת. נא לנסות לציין <var>fromtitle</var> או <var>totitle</var>.",
+ "apierror-compare-nosuchfromsection": "הפסקה $1 אינה קיימת בתוכן של 'from'.",
+ "apierror-compare-nosuchtosection": "הפסקה $1 אינה קיימת בתוכן של 'to'.",
"apierror-compare-relative-to-nothing": "אין גרסת \"from\" עבור <var>torelative</var> שתהיה יחסית.",
"apierror-contentserializationexception": "הסדרת התוכן נכשלה: $1",
"apierror-contenttoobig": "התוכן שסיפקת חורג מגודל הערך המרבי של {{PLURAL:$1|קילובייט אחד|$1 קילובייטים}}.",
"apierror-invalidurlparam": "ערך בלתי־תקין עבור <var>$1urlparam</var> (ערך: <kbd>$2=$3</kbd>).",
"apierror-invaliduser": "שם משתמש בלתי־תקין \"$1\".",
"apierror-invaliduserid": "מזהה המשתמש <var>$1</var> אינו תקין.",
+ "apierror-maxbytes": "הפרמטר <var>$1</var> לא יכול להיות ארוך יותר {{PLURAL:$2|מבייט אחד|מ־$2 בייטים}}",
+ "apierror-maxchars": "הפרמטר <var>$1</var> לא יכול להיות ארוך יותר {{PLURAL:$2|מתו אחד|מ־$2 תווים}}",
"apierror-maxlag-generic": "ממתין לשרת מסד נתונים: עיכוב של {{PLURAL:$1|שנייה אחת|$1 שניות}}.",
"apierror-maxlag": "ממתין ל־$2: שיהוי של {{PLURAL:$1|שנייה אחת|$1 שניות}}.",
"apierror-mimesearchdisabled": "חיפוש MIME כבוי במצב קמצן.",
"apihelp-block-param-tags": "ブロック記録の項目に適用する変更タグ。",
"apihelp-block-example-ip-simple": "IPアドレス <kbd>192.0.2.5</kbd> を <kbd>First strike<kbd> という理由で3日ブロックする",
"apihelp-block-example-user-complex": "利用者 <kbd>Vandal</kbd> を <kbd>Vandalism</kbd> という理由で無期限ブロックし、新たなアカウント作成とメールの送信を禁止する。",
+ "apihelp-changeauthenticationdata-summary": "現在の利用者の認証データを変更します。",
"apihelp-changeauthenticationdata-example-password": "現在の利用者のパスワードを <kbd>ExamplePassword</kbd> に変更する。",
"apihelp-checktoken-summary": "<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> のトークンの妥当性を確認します。",
"apihelp-checktoken-param-type": "調べるトークンの種類。",
"apihelp-checktoken-example-simple": "<kbd>csrf</kbd> トークンの妥当性を調べる。",
"apihelp-clearhasmsg-summary": "現在の利用者の <code>hasmsg</code> フラグを消去します。",
"apihelp-clearhasmsg-example-1": "現在の利用者の <code>hasmsg</code> フラグを消去する。",
+ "apihelp-clientlogin-summary": "インタラクティブフローを使用してウィキにログインします。",
"apihelp-clientlogin-example-login": "利用者 <kbd>Example</kbd> としてのログイン処理をパスワード <kbd>ExamplePassword</kbd> で開始する",
+ "apihelp-clientlogin-example-login2": "<kbd>987654</kbd>の<var>OATHToken</var>を提供する2段階認証の<samp>UI</samp>レスポンスの後にログインを続けます。",
"apihelp-compare-summary": "2つの版間の差分を取得します。",
"apihelp-compare-extended-description": "\"from\" と \"to\" の両方の版番号、ページ名、もしくはページIDを渡す必要があります。",
"apihelp-compare-param-fromtitle": "比較する1つ目のページ名。",
"apihelp-compare-param-fromid": "比較する1つ目のページID。",
"apihelp-compare-param-fromrev": "比較する1つ目の版。",
+ "apihelp-compare-param-frompst": "<var>fromtext</var>に保存前変換を行います。",
+ "apihelp-compare-param-fromcontentmodel": "<var>fromtext</var>のコンテンツモデル。指定されていない場合は、他のパラメータに基づいて推測されます。",
"apihelp-compare-param-totitle": "比較する2つ目のページ名。",
"apihelp-compare-param-toid": "比較する2つ目のページID。",
"apihelp-compare-param-torev": "比較する2つ目の版。",
+ "apihelp-compare-param-topst": "<var>totext</var>に保存前変換を行います。",
"apihelp-compare-param-prop": "どの情報を取得するか:",
"apihelp-compare-paramvalue-prop-diff": "差分HTML。",
"apihelp-compare-paramvalue-prop-diffsize": "差分HTMLのサイズ (バイト数)。",
"apihelp-compare-paramvalue-prop-size": "'from' および 'to' の版のサイズ。",
"apihelp-compare-example-1": "版1と2の差分を生成する。",
"apihelp-createaccount-summary": "新しい利用者アカウントを作成します。",
+ "apihelp-createaccount-example-create": "利用者 <kbd>Example</kbd> を作成する処理をパスワード <kbd>ExamplePassword</kbd> で開始する",
"apihelp-createaccount-param-name": "利用者名。",
"apihelp-createaccount-param-password": "パスワード (<var>$1mailpassword</var> が設定されると無視されます)。",
"apihelp-createaccount-param-domain": "外部認証のドメイン (省略可能)。",
"apihelp-createaccount-param-language": "利用者の言語コードの既定値 (省略可能, 既定ではコンテンツ言語)。",
"apihelp-createaccount-example-pass": "利用者 <kbd>testuser</kbd> をパスワード <kbd>test123</kbd> として作成する。",
"apihelp-createaccount-example-mail": "利用者 <kbd>testmailuser</kbd>を作成し、無作為に生成されたパスワードをメールで送る。",
+ "apihelp-cspreport-param-source": "このレポートをトリガしたCSPヘッダを生成した内容",
"apihelp-delete-summary": "ページを削除します。",
"apihelp-delete-param-title": "削除するページ名です。<var>$1pageid</var> とは同時に使用できません。",
"apihelp-delete-param-pageid": "削除するページIDです。<var>$1title</var> とは同時に使用できません。",
"apihelp-edit-param-bot": "この編集をボットの編集としてマークする。",
"apihelp-edit-param-basetimestamp": "編集前の版のタイムスタンプ。編集競合を検出するために使用されます。\n[[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]] で取得できます。",
"apihelp-edit-param-starttimestamp": "編集作業を開始したときのタイムスタンプ。編集競合を検出するために使用されます。適切な値は <var>[[Special:ApiHelp/main|curtimestamp]]</var> を使用して編集作業を開始するとき (たとえば、編集するページの本文を読み込んだとき) に取得できます。",
+ "apihelp-edit-param-recreate": "その間に削除されたページに関するエラーを上書きします。",
"apihelp-edit-param-createonly": "すでにそのページが存在する場合は編集を行いません。",
"apihelp-edit-param-nocreate": "そのページが存在しない場合にエラーを返します。",
"apihelp-edit-param-watch": "そのページを現在の利用者のウォッチリストに追加します。",
"apihelp-edit-param-undo": "この版を取り消します。$1text, $1prependtext および $1appendtext をオーバーライドします。",
"apihelp-edit-param-undoafter": "$1undo からこの版までのすべての版を取り消します。設定しない場合、ひとつの版のみ取り消されます。",
"apihelp-edit-param-redirect": "自動的に転送を解決します。",
+ "apihelp-edit-param-contentmodel": "新しいコンテンツのコンテンツ・モデル。",
"apihelp-edit-param-token": "このトークンは常に最後のパラメーターとして、または少なくとも $1text パラメーターより後に送信されるべきです。",
"apihelp-edit-example-edit": "ページを編集",
"apihelp-edit-example-prepend": "<kbd>__NOTOC__</kbd> をページの先頭に挿入する。",
"apihelp-expandtemplates-param-title": "ページの名前です。",
"apihelp-expandtemplates-param-text": "変換するウィキテキストです。",
"apihelp-expandtemplates-paramvalue-prop-wikitext": "展開されたウィキテキスト。",
+ "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "ページに固有のJavaScriptの設定変数を提供します。",
+ "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "JSON文字列としてページに固有のJavaScriptの設定変数を提供します。",
"apihelp-expandtemplates-paramvalue-prop-parsetree": "入力のXML構文解析ツリー。",
"apihelp-expandtemplates-param-includecomments": "HTMLコメントを出力に含めるかどうか。",
"apihelp-expandtemplates-param-generatexml": "XMLの構文解析ツリーを生成します (replaced by $1prop=parsetree)",
"apihelp-feedrecentchanges-param-namespace": "この名前空間の結果のみに絞り込む。",
"apihelp-feedrecentchanges-param-invert": "選択されたものを除く、すべての名前空間。",
"apihelp-feedrecentchanges-param-associated": "関連する(トークまたはメイン)名前空間を含めます。",
+ "apihelp-feedrecentchanges-param-days": "結果を絞り込む日数。",
"apihelp-feedrecentchanges-param-limit": "返す結果の最大数。",
"apihelp-feedrecentchanges-param-from": "これ以降の編集を表示する。",
"apihelp-feedrecentchanges-param-hideminor": "細部の変更を隠す。",
"apihelp-feedrecentchanges-param-hideliu": "登録利用者による変更を隠す。",
"apihelp-feedrecentchanges-param-hidepatrolled": "巡回済みの変更を隠す。",
"apihelp-feedrecentchanges-param-hidemyself": "現在の利用者による編集を非表示にする。",
+ "apihelp-feedrecentchanges-param-hidecategorization": "カテゴリのメンバーの変更を非表示にする。",
"apihelp-feedrecentchanges-param-tagfilter": "タグにより絞り込む。",
"apihelp-feedrecentchanges-param-target": "このページからリンクされているページの変更のみを表示する。",
+ "apihelp-feedrecentchanges-param-showlinkedto": "選択したページへのリンク元での変更の表示に切り替え",
"apihelp-feedrecentchanges-example-simple": "最近の更新を表示する。",
"apihelp-feedrecentchanges-example-30days": "最近30日間の変更を表示する。",
"apihelp-feedwatchlist-summary": "ウォッチリストのフィードを返します。",
"apihelp-help-example-query": "2つの下位モジュールのヘルプ",
"apihelp-imagerotate-summary": "1つ以上の画像を回転させます。",
"apihelp-imagerotate-param-rotation": "画像を回転させる時計回りの角度。",
+ "apihelp-imagerotate-param-tags": "アップロード記録の項目に適用するタグ。",
"apihelp-imagerotate-example-simple": "<kbd>File:Example.png</kbd> を <kbd>90</kbd> 度回転させる。",
"apihelp-imagerotate-example-generator": "<kbd>Category:Flip</kbd> 内のすべての画像を <kbd>180</kbd> 度回転させる。",
"apihelp-import-summary": "他のWikiまたはXMLファイルからページを取り込む。",
"apihelp-import-extended-description": "<var>xml</var> パラメーターでファイルを送信する場合、ファイルのアップロードとしてHTTP POSTされなければならない (例えば、multipart/form-dataを使用する) 点に注意してください。",
"apihelp-import-param-summary": "記録されるページ取り込みの要約。",
"apihelp-import-param-xml": "XMLファイルをアップロード",
+ "apihelp-import-param-assignknownusers": "指定されたユーザーがこのウィキに存在する場合そのユーザーに編集を割り当てる",
"apihelp-import-param-interwikisource": "ウィキ間の取り込みの場合: 取り込み元のウィキ。",
"apihelp-import-param-interwikipage": "ウィキ間の取り込みの場合: 取り込むページ。",
"apihelp-import-param-fullhistory": "ウィキ間の取り込みの場合: 現在の版のみではなく完全な履歴を取り込む。",
"apihelp-import-param-rootpage": "このページの下位ページとして取り込む。<var>$1namespace</var> パラメータとは同時に使用できません。",
"apihelp-import-example-import": "[[meta:Help:ParserFunctions]] をすべての履歴とともに名前空間100に取り込む。",
"apihelp-login-summary": "ログインして認証クッキーを取得します。",
- "apihelp-login-extended-description": "ã\83ã\82°ã\82¤ã\83³ã\81\8cæ\88\90å\8a\9fã\81\97ã\81\9få ´å\90\88ã\80\81å¿\85è¦\81ã\81ªã\82¯ã\83\83ã\82ã\83¼ã\81¯ HTTP å¿\9cç\94ã\83\98ã\83\83ã\83\80ã\81«å\90«ã\81¾ã\82\8cã\81¾ã\81\99ã\80\82ã\83ã\82°ã\82¤ã\83³ã\81«å¤±æ\95\97ã\81\97ã\81\9få ´å\90\88ã\80\81è\87ªå\8b\95å\8c\96ã\81®ã\83\91ã\82¹ã\83¯ã\83¼ã\83\89æ\8e¨å®\9aæ\94»æ\92\83ã\82\92å\88¶é\99\90ã\81\99ã\82\8bã\81\9fã\82\81ã\81«ã\80\81追å\8a ã\81®è©¦è¡\8cã\81¯é\80\9f度å\88¶é\99\90ã\81\95ã\82\8cã\82\8bã\81\93ã\81¨ã\81\8cã\81\82ã\82\8aます。",
+ "apihelp-login-extended-description": "ã\81\93ã\81®ã\82¢ã\82¯ã\82·ã\83§ã\83³ã\81¯ã\80\81[[Special:BotPasswords]]ã\81¨çµ\84ã\81¿å\90\88ã\82\8fã\81\9bã\81¦ä½¿ç\94¨ã\81\99ã\82\8bå¿\85è¦\81ã\81\8cã\81\82ã\82\8aã\81¾ã\81\99ã\80\82ã\83¡ã\82¤ã\83³ã\82¢ã\82«ã\82¦ã\83³ã\83\88ã\81®ã\83ã\82°ã\82¤ã\83³ã\81«ä½¿ç\94¨ã\81\99ã\82\8bã\81\93ã\81¨ã\81¯æ\8e¨å¥¨ã\81\95ã\82\8cã\81ªã\81\8fã\81ªã\82\8aã\80\81è¦å\91\8aã\81ªã\81\8f失æ\95\97ã\81\99ã\82\8bå\8f¯è\83½æ\80§ã\81\8cã\81\82ã\82\8aã\81¾ã\81\99ã\80\82ã\83¡ã\82¤ã\83³ã\82¢ã\82«ã\82¦ã\83³ã\83\88ã\81«å®\89å\85¨ã\81«ã\83ã\82°ã\82¤ã\83³ã\81\99ã\82\8bã\81«ã\81¯ã\80\81<kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>ã\82\92使ç\94¨ã\81\97ます。",
"apihelp-login-param-name": "利用者名。",
"apihelp-login-param-password": "パスワード。",
"apihelp-login-param-domain": "ドメイン (省略可能)",
"apihelp-managetags-param-tag": "作成、削除、有効化、または無効化するタグ。タグの作成の場合、そのタグは存在しないものでなければなりません。タグの削除の場合、そのタグが存在しなければなりません。タグの有効化の場合、そのタグが存在し、かつ拡張機能によって使用されていないものでなければなりません。タグの無効化の場合、そのタグが現在有効であって手動で定義されたものでなければなりません。",
"apihelp-managetags-param-reason": "タグを作成、削除、有効化、または無効化する追加の理由。",
"apihelp-managetags-param-ignorewarnings": "操作中に発生したすべての警告を無視するかどうか。",
+ "apihelp-managetags-param-tags": "タグを変更し、タグ管理記録の項目に適用します。",
"apihelp-managetags-example-create": "<kbd>spam</kbd> という名前のタグを <kbd>For use in edit patrolling</kbd> という理由で作成する",
"apihelp-managetags-example-delete": "<kbd>vandlaism</kbd> タグを <kbd>Misspelt</kbd> という理由で削除する",
"apihelp-managetags-example-activate": "<kbd>spam</kbd> という名前のタグを <kbd>For use in edit patrolling</kbd> という理由で有効化する",
"apihelp-purge-param-forcelinkupdate": "リンクテーブルを更新します。",
"apihelp-purge-example-simple": "ページ <kbd>Main Page</kbd> および <kbd>API</kbd> をパージする。",
"apihelp-purge-example-generator": "標準名前空間にある最初の10ページをパージする。",
+ "apihelp-query-summary": "MediaWikiからデータを取得します。",
"apihelp-query-param-prop": "照会ページ用に、どのプロパティを取得するか。",
"apihelp-query-param-list": "どの一覧を取得するか。",
"apihelp-query-param-meta": "どのメタデータを取得するか。",
"apihelp-query+allfileusages-param-from": "列挙を開始するファイルのページ名。",
"apihelp-query+allfileusages-param-to": "列挙を終了するファイルのページ名。",
"apihelp-query+allfileusages-param-prefix": "この値で始まるページ名のすべてのファイルを検索する。",
+ "apihelp-query+allfileusages-param-unique": "ファイル名を一度だけ表示します。<kbd>$1prop=ids</kbd> とは同時に使用できません。ジェネレーターとして使用される場合、リンク元ではなくリンク先のページを生成します。",
"apihelp-query+allfileusages-param-prop": "どの情報を結果に含めるか:",
"apihelp-query+allfileusages-paramvalue-prop-ids": "使用しているページのページIDを追加します ($1unique とは同時に使用できません)。",
"apihelp-query+allfileusages-paramvalue-prop-title": "ファイルのページ名を追加します。",
"apihelp-query+allpages-param-to": "列挙を終了するページ名。",
"apihelp-query+allpages-param-prefix": "この値で始まるすべてのページ名を検索します。",
"apihelp-query+allpages-param-namespace": "列挙する名前空間。",
+ "apihelp-query+allpages-param-filterredir": "リストするページ",
"apihelp-query+allpages-param-minsize": "ページの最低バイト数を制限する。",
"apihelp-query+allpages-param-maxsize": "ページの最大バイト数を制限する。",
"apihelp-query+allpages-param-prtype": "保護されているページに絞り込む。",
"apihelp-query+allredirects-param-prefix": "この値で始まるすべてのページを検索する。",
"apihelp-query+allredirects-param-unique": "転送先ページ名を一度だけ表示します。<kbd>$1prop=ids|fragment|interwiki</kbd> とは同時に使用できません。ジェネレーターとして使用される場合、転送元ではなく転送先のページを生成します。",
"apihelp-query+allredirects-param-prop": "どの情報を結果に含めるか:",
+ "apihelp-query+allredirects-paramvalue-prop-ids": "転送ページのページIDを追加します ($1unique とは同時に使用できません)。",
"apihelp-query+allredirects-paramvalue-prop-title": "転送ページのページ名を追加します。",
"apihelp-query+allredirects-param-namespace": "列挙する名前空間。",
"apihelp-query+allredirects-param-limit": "返す項目の総数。",
"apihelp-query+allredirects-param-dir": "一覧表示する方向。",
"apihelp-query+allredirects-example-B": "<kbd>B</kbd> で始まる転送先ページ (存在しないページも含む)を、転送元のページIDとともに表示する。",
+ "apihelp-query+allredirects-example-unique": "一意のターゲットページを一覧表示します。",
+ "apihelp-query+allredirects-example-unique-generator": "存在しないものに印をつけて、すべて取得する。",
+ "apihelp-query+allredirects-example-generator": "リダイレクトを含むページを取得します。",
"apihelp-query+allrevisions-summary": "すべての版を一覧表示する。",
"apihelp-query+allrevisions-param-start": "列挙の始点となるタイムスタンプ。",
"apihelp-query+allrevisions-param-end": "列挙の終点となるタイムスタンプ。",
"apihelp-query+prefixsearch-param-namespace": "検索する名前空間。<var>$1search</var>が有効な名前空間接頭辞で始まる場合は無視されます。",
"apihelp-query+prefixsearch-param-limit": "返す結果の最大数。",
"apihelp-query+prefixsearch-example-simple": "<kbd>meaning</kbd> で始まるページ名を検索する。",
+ "apihelp-query+prefixsearch-param-profile": "使用するプロファイルを検索します。",
"apihelp-query+protectedtitles-summary": "作成保護が掛けられているページを一覧表示します。",
"apihelp-query+protectedtitles-param-namespace": "この名前空間に含まれるページのみを一覧表示します。",
"apihelp-query+protectedtitles-param-level": "この保護レベルのページのみを一覧表示します。",
"apihelp-query+querypage-param-page": "特別ページの名前です。これは大文字小文字を区別することに注意。",
"apihelp-query+querypage-param-limit": "返す結果の数。",
"apihelp-query+querypage-example-ancientpages": "[[Special:Ancientpages]] の結果を返す。",
+ "apihelp-query+random-summary": "ランダムなページのセットを取得します。",
"apihelp-query+random-param-namespace": "この名前空間にあるページのみを返します。",
"apihelp-query+random-param-limit": "返す無作為なページの数を制限する。",
"apihelp-query+random-param-redirect": "代わりに <kbd>$1filterredir=redirects</kbd> を使用してください。",
"apihelp-query+recentchanges-paramvalue-prop-redirect": "編集されたページが転送ページである場合、印を付けます。",
"apihelp-query+recentchanges-paramvalue-prop-patrolled": "巡回可能な編集について、巡回済みかどうか印を付けます。",
"apihelp-query+recentchanges-paramvalue-prop-loginfo": "記録項目に記録の情報 (記録ID, 記録タイプなど) を追加します。",
+ "apihelp-query+recentchanges-paramvalue-prop-tags": "エントリのタグを一覧表示します。",
"apihelp-query+recentchanges-param-token": "代わりに <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> を使用してください。",
"apihelp-query+recentchanges-param-limit": "返す変更の総数。",
"apihelp-query+recentchanges-param-toponly": "最新の版である変更のみを一覧表示する。",
"apihelp-query+search-param-search": "この値を含むページ名または本文を検索します。Wikiの検索バックエンド実装に応じて、あなたは特別な検索機能を呼び出すための文字列を検索することができます。",
"apihelp-query+search-param-namespace": "この名前空間内のみを検索します。",
"apihelp-query+search-param-what": "実行する検索の種類です。",
+ "apihelp-query+search-param-info": "どのメタデータを返すか。",
"apihelp-query+search-param-prop": "返すプロパティ:",
"apihelp-query+search-paramvalue-prop-size": "バイト単位のページのサイズを追加します。",
"apihelp-query+search-paramvalue-prop-wordcount": "ページのワード数を追加します。",
"apihelp-query+templates-summary": "与えられたページでトランスクルードされているすべてのページを返します。",
"apihelp-query+templates-param-namespace": "この名前空間のテンプレートのみ表示する。",
"apihelp-query+templates-param-limit": "返すテンプレートの数。",
+ "apihelp-query+templates-param-dir": "一覧表示する方向。",
"apihelp-query+templates-example-simple": "<kbd>Main Page</kbd> で使用されているテンプレートを取得する。",
"apihelp-query+templates-example-generator": "<kbd>Main Page</kbd> で使用されているテンプレートに関する情報を取得する。",
"apihelp-query+templates-example-namespaces": "<kbd>Main Page</kbd> でトランスクルードされている {{ns:user}} および {{ns:template}} 名前空間のページを取得する。",
"apihelp-query+transcludedin-param-prop": "取得するプロパティ:",
"apihelp-query+transcludedin-paramvalue-prop-pageid": "各ページのページID。",
"apihelp-query+transcludedin-paramvalue-prop-title": "各ページのページ名。",
+ "apihelp-query+transcludedin-paramvalue-prop-redirect": "ページがリダイレクトである場合マークします。",
+ "apihelp-query+transcludedin-param-namespace": "この名前空間に含まれるページのみを一覧表示します。",
+ "apihelp-query+transcludedin-param-limit": "返す数。",
"apihelp-query+transcludedin-example-simple": "<kbd>Main Page</kbd> をトランスクルードしているページの一覧を取得する。",
"apihelp-query+transcludedin-example-generator": "<kbd>Main Page</kbd> をトランスクルードしているページに関する情報を取得する。",
"apihelp-query+usercontribs-summary": "利用者によるすべての編集を取得します。",
"apihelp-revisiondelete-summary": "版の削除および復元を行います。",
"apihelp-revisiondelete-param-reason": "削除または復元の理由。",
"apihelp-revisiondelete-example-revision": "<kbd>Main Page</kbd> の版 <kbd>12345</kbd> の本文を隠す。",
+ "apihelp-rollback-summary": "ページの最後の編集を取り消す。",
"apihelp-rollback-param-title": "巻き戻すページ名です。<var>$1pageid</var> とは同時に使用できません。",
"apihelp-rollback-param-pageid": "巻き戻すページのページIDです。<var>$1title</var> とは同時に使用できません。",
"apihelp-rollback-param-tags": "巻き戻しに適用するタグ。",
"apihelp-tokens-example-edit": "編集トークンを取得する (既定)。",
"apihelp-unblock-summary": "利用者のブロックを解除します。",
"apihelp-unblock-param-id": "解除するブロックのID (<kbd>list=blocks</kbd>で取得できます)。<var>$1user</var> または <var>$1userid</var> とは同時に使用できません。",
- "apihelp-unblock-param-user": "ã\83\96ã\83ã\83\83ã\82¯ã\82\92解é\99¤ã\81\99ã\82\8bå\88©ç\94¨è\80\85å\90\8dã\80\81IPã\82¢ã\83\89ã\83¬ã\82¹ã\81¾ã\81\9fã\81¯IPã\83¬ã\83³ã\82¸ã\80\82<var>$1id</var>とは同時に使用できません。",
+ "apihelp-unblock-param-user": "ã\83\96ã\83ã\83\83ã\82¯ã\82\92解é\99¤ã\81\99ã\82\8bå\88©ç\94¨è\80\85å\90\8dã\80\81IPã\82¢ã\83\89ã\83¬ã\82¹ã\81¾ã\81\9fã\81¯IPã\82¢ã\83\89ã\83¬ã\82¹ã\83¬ã\83³ã\82¸ã\80\82<var>$1id</var>ã\81¾ã\81\9fã\81¯<var>$1userid</var>とは同時に使用できません。",
"apihelp-unblock-param-reason": "ブロック解除の理由。",
"apihelp-unblock-param-tags": "ブロック記録の項目に適用する変更タグ。",
"apihelp-unblock-example-id": "ブロックID #<kbd>105</kbd> を解除する。",
"api-help-flag-writerights": "このモジュールは書き込みの権限を必要とします。",
"api-help-flag-mustbeposted": "このモジュールは POST リクエストのみを受け付けます。",
"api-help-flag-generator": "このモジュールはジェネレーターとして使用できます。",
+ "api-help-source": "ソース: $1",
"api-help-parameters": "{{PLURAL:$1|パラメーター}}:",
"api-help-param-deprecated": "廃止予定です。",
"api-help-param-required": "このパラメーターは必須です。",
"api-help-permissions": "{{PLURAL:$1|権限}}:",
"api-help-permissions-granted-to": "{{PLURAL:$1|権限を持つグループ}}: $2",
"api-help-open-in-apisandbox": "<small>[サンドボックスで開く]</small>",
+ "apierror-filedoesnotexist": "ファイルが存在しません。",
+ "apierror-invaliduser": "無効なユーザー名「$1」。",
"apierror-missingparam": "パラメーター <var>$1</var> を設定してください。",
+ "apierror-mustbeloggedin": "$1にログインしている必要があります。",
+ "apierror-noimageredirect": "画像のリダイレクトを作成する権限がありません。",
+ "apierror-nosuchpageid": "ID $1のページはありません。",
+ "apierror-permissiondenied": "$1に必要な権限がありません。",
+ "apierror-permissiondenied-generic": "アクセスが拒否されました。",
+ "apierror-readonly": "ウィキは現在読み取り専用モードです。",
"apierror-timeout": "サーバーが決められた時間内に応答しませんでした。",
+ "apierror-unknownerror-editpage": "不明な編集ページのエラー:$1",
+ "apierror-unknownerror-nocode": "不明なエラーです。",
+ "apierror-unknownerror": "不明なエラー:「$1」",
"apiwarn-invalidcategory": "「$1」はカテゴリではありません。",
"apiwarn-notfile": "「$1」はファイルではありません。",
+ "apiwarn-validationfailed-cannotset": "このモジュールでは設定できません。",
+ "apiwarn-validationfailed-keytoolong": "キーが長すぎます($1バイト以上は許可されません)。",
+ "apiwarn-wgDebugAPI": "<strong>セキュリティ警告</strong>:<var>$wgDebugAPI</var>が有効です。",
+ "api-feed-error-title": "エラー ($1)",
+ "api-usage-docref": "APIの使用については$1を参照してください。",
+ "api-exception-trace": "$2の$1($3)\n$4",
"api-credits-header": "クレジット",
"api-credits": "API の開発者:\n* Roan Kattouw (2007年9月-2009年の主任開発者)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (作成者、2006年9月-2007年9月の主任開発者)\n* Brad Jorsch (2013年-現在の主任開発者)\n\nコメント、提案、質問は mediawiki-api@lists.wikimedia.org にお送りください。\nバグはこちらへご報告ください: https://phabricator.wikimedia.org/"
}
"api-help-permissions": "{{PLURAL:$1|權限}}:",
"api-help-permissions-granted-to": "{{PLURAL:$1|已授權給}}: $2",
"api-help-authmanager-general-usage": "使用此模組的一般程式是:\n# 通過<kbd>amirequestsfor=$4</kbd>取得來自<kbd>[[Special:ApiHelp/query+authmanagerinfo|action=query&meta=authmanagerinfo]]</kbd>的可用欄位,和來自<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>的<kbd>$5</kbd>令牌。\n# 向用戶顯示欄位,並獲得其提交的內容。\n# 提交(POST)至此模組,提供<var>$1returnurl</var>及任何相關欄位。\n# 在回应中檢查<samp>status</samp>。\n#* 如果您收到了<samp>PASS</samp>(成功)或<samp>FAIL</samp>(失敗),則認為操作結束。成功與否如上句所示。\n#* 如果您收到了<samp>UI</samp>,向用戶顯示新欄位,並再次獲取其提交的內容。然後再次使用<var>$1continue</var>,向本模組提交相關欄位,並重復第四步。\n#* 如果您收到了<samp>REDIRECT</samp>,將使用者指向<samp>redirecttarget</samp>中的目標,等待其返回<var>$1returnurl</var>。然後再次使用<var>$1continue</var>,向本模組提交返回URL中提供的一切欄位,並重復第四步。\n#* 如果您收到了<samp>RESTART</samp>,這意味著身份驗證正常運作,但我們沒有連結的使用者賬戶。您可以將此看做<samp>UI</samp>或<samp>FAIL</samp>。",
+ "apierror-missingparam": "<var>$1</var>參數必須被設定。",
"apierror-mustbeloggedin-changeauth": "必須登入,才能變更身分核對資取。",
"apierror-mustbeloggedin-removeauth": "必須登入,才能移除身分核對資取。",
"apierror-permissiondenied": "您沒有權限$1。",
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "Liuxinyu970226"
+ ]
+ },
+ "apihelp-block-param-hidename": "隱藏封鎖日誌的用戶名稱。 (需要 \"hideuser\" 權限)。",
+ "apihelp-block-param-allowusertalk": "允許用戶編輯自己的對話頁面 (依據 <var>[[mw:Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var> 的設定)。",
+ "apihelp-block-param-reblock": "若用戶已被封鎖,覆寫既有的封鎖設定值。",
+ "apihelp-block-param-watchuser": "監視用戶或 IP 的用戶頁面與對話頁面。",
+ "apihelp-createaccount-summary": "建立一個新用戶戶口。",
+ "apihelp-login-param-name": "用戶名稱。",
+ "apihelp-userrights-param-user": "用戶名稱。",
+ "apihelp-userrights-param-userid": "用戶 ID。"
+}
const PRC_PATROLLED = 1;
const PRC_AUTOPATROLLED = 2;
+ /**
+ * @var bool For save() - save to the database only, without any events.
+ */
+ const SEND_NONE = true;
+
+ /**
+ * @var bool For save() - do emit the change to RCFeeds (usually public).
+ */
+ const SEND_FEED = false;
+
public $mAttribs = [];
public $mExtra = [];
/**
* Writes the data in this object to the database
- * @param bool $noudp
+ *
+ * For compatibility reasons, the SEND_ constants internally reference a value
+ * that may seem negated from their purpose (none=true, feed=false). This is
+ * because the parameter used to be called "$noudp", defaulting to false.
+ *
+ * @param bool $send self::SEND_FEED or self::SEND_NONE
*/
- public function save( $noudp = false ) {
+ public function save( $send = self::SEND_FEED ) {
global $wgPutIPinRC, $wgUseEnotif, $wgShowUpdatedMarker;
+ if ( is_string( $send ) ) {
+ // Callers used to pass undocumented strings like 'noudp'
+ // or 'pleasedontudp' instead of self::SEND_NONE (true).
+ // @deprecated since 1.31 Use SEND_NONE instead.
+ $send = self::SEND_NONE;
+ }
+
$dbw = wfGetDB( DB_MASTER );
if ( !is_array( $this->mExtra ) ) {
$this->mExtra = [];
$this->mAttribs['rc_this_oldid'], $this->mAttribs['rc_logid'], null, $this );
}
- # Notify external application via UDP
- if ( !$noudp ) {
+ if ( $send === self::SEND_FEED ) {
+ // Emit the change to external applications via RCFeeds.
$this->notifyRCFeeds();
}
<?php
+use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\LoadBalancer;
* @return IDatabase
*/
protected function getConnection( $id, $groups = [] ) {
- $loadBalancer = wfGetLB( $this->wiki );
+ $loadBalancer = $this->getLoadBalancer();
return $loadBalancer->getConnection( $id, $groups, $this->wiki );
}
/**
* Get the database type used for read operations.
*
- * @see wfGetLB
+ * @see MediaWikiServices::getDBLoadBalancer
*
* @since 1.21
*
* @return LoadBalancer The database load balancer object
*/
public function getLoadBalancer() {
- return wfGetLB( $this->wiki );
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ return $lbFactory->getMainLB( $this->wiki );
}
}
* Updates that work through this system will be more likely to complete by the time the client
* makes their next request after this one than with the JobQueue system.
*
- * In CLI mode, updates run immediately if no DB writes are pending. Otherwise, they run when:
- * - a) Any waitForReplication() call if no writes are pending on any DB
- * - b) A commit happens on Maintenance::getDB( DB_MASTER ) if no writes are pending on any DB
- * - c) EnqueueableDataUpdate tasks may enqueue on commit of Maintenance::getDB( DB_MASTER )
- * - d) At the completion of Maintenance::execute()
+ * In CLI mode, deferred updates will run:
+ * - a) During DeferredUpdates::addUpdate if no LBFactory DB handles have writes pending
+ * - b) On commit of an LBFactory DB handle if no other such handles have writes pending
+ * - c) During an LBFactory::waitForReplication call if no LBFactory DBs have writes pending
+ * - d) When the queue is large and an LBFactory DB handle commits (EnqueueableDataUpdate only)
+ * - e) At the completion of Maintenance::execute()
+ *
+ * @see Maintenance::setLBFactoryTriggers
*
* When updates are deferred, they go into one two FIFO "top-queues" (one for pre-send and one
* for post-send). Updates enqueued *during* doUpdate() of a "top" update go into the "sub-queue"
foreach ( $updatesByType as $updatesForType ) {
foreach ( $updatesForType as $update ) {
self::$executeContext = [ 'stage' => $stage, 'subqueue' => [] ];
- /** @var DeferrableUpdate $update */
- $guiError = self::runUpdate( $update, $lbFactory, $mode, $stage );
- $reportableError = $reportableError ?: $guiError;
- // Do the subqueue updates for $update until there are none
- while ( self::$executeContext['subqueue'] ) {
- $subUpdate = reset( self::$executeContext['subqueue'] );
- $firstKey = key( self::$executeContext['subqueue'] );
- unset( self::$executeContext['subqueue'][$firstKey] );
-
- if ( $subUpdate instanceof DataUpdate ) {
- $subUpdate->setTransactionTicket( $ticket );
- }
-
- $guiError = self::runUpdate( $subUpdate, $lbFactory, $mode, $stage );
+ try {
+ /** @var DeferrableUpdate $update */
+ $guiError = self::runUpdate( $update, $lbFactory, $mode, $stage );
$reportableError = $reportableError ?: $guiError;
+ // Do the subqueue updates for $update until there are none
+ while ( self::$executeContext['subqueue'] ) {
+ $subUpdate = reset( self::$executeContext['subqueue'] );
+ $firstKey = key( self::$executeContext['subqueue'] );
+ unset( self::$executeContext['subqueue'][$firstKey] );
+
+ if ( $subUpdate instanceof DataUpdate ) {
+ $subUpdate->setTransactionTicket( $ticket );
+ }
+
+ $guiError = self::runUpdate( $subUpdate, $lbFactory, $mode, $stage );
+ $reportableError = $reportableError ?: $guiError;
+ }
+ } finally {
+ // Make sure we always clean up the context.
+ // Losing updates while rewinding the stack is acceptable,
+ // losing updates that are added later is not.
+ self::$executeContext = null;
}
- self::$executeContext = null;
}
}
$guiError = $e;
}
MWExceptionHandler::rollbackMasterChangesAndLog( $e );
+
+ // VW-style hack to work around T190178, so we can make sure
+ // PageMetaDataUpdater doesn't throw exceptions.
+ if ( defined( 'MW_PHPUNIT_TEST' ) ) {
+ throw $e;
+ }
}
return $guiError;
/**
* Run all deferred updates immediately if there are no DB writes active
*
- * If $mode is 'run' but there are busy databates, EnqueueableDataUpdate
- * tasks will be enqueued anyway for the sake of progress.
+ * If there are many deferred updates pending, $mode is 'run', and there
+ * are still busy LBFactory database handles, then any EnqueueableDataUpdate
+ * tasks might be enqueued as jobs to be executed later.
*
* @param string $mode Use "enqueue" to use the job queue when possible
* @return bool Whether updates were allowed to run
*/
private static function areDatabaseTransactionsActive() {
$lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
- if ( $lbFactory->hasTransactionRound() ) {
+ if ( $lbFactory->hasTransactionRound() || !$lbFactory->isReadyForRoundOperations() ) {
return true;
}
// Commit and release the lock (if set)
ScopedCallback::consume( $scopedLock );
- // Run post-commit hooks without DBO_TRX
- $this->getDB()->onTransactionIdle(
+ // Run post-commit hook handlers without DBO_TRX
+ DeferredUpdates::addUpdate( new AutoCommitUpdate(
+ $this->getDB(),
+ __METHOD__,
function () {
// Avoid PHP 7.1 warning from passing $this by reference
$linksUpdate = $this;
Hooks::run( 'LinksUpdateComplete', [ &$linksUpdate, $this->ticket ] );
- },
- __METHOD__
- );
+ }
+ ) );
}
/**
+++ /dev/null
-<?php
-/**
- * Base code for update jobs that put some secondary data extracted
- * from article content into the database.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * @deprecated Since 1.28 Use DataUpdate directly, injecting the database
- */
-abstract class SqlDataUpdate extends DataUpdate {
- /** @var IDatabase Database connection reference */
- protected $mDb;
- /** @var array SELECT options to be used (array) */
- protected $mOptions = [];
-
- public function __construct() {
- parent::__construct();
-
- $this->mDb = wfGetLB()->getLazyConnectionRef( DB_MASTER );
- }
-}
*/
use MediaWiki\Diff\ComplexityException;
+// FIXME: Don't use assert() in this file
+// phpcs:disable MediaWiki.Usage.ForbiddenFunctions.assert
+
/**
* This diff implementation is mainly lifted from the LCS algorithm of the Eclipse project which
* in turn is based on Myers' "An O(ND) difference algorithm and its variations"
$this->flushLine( $tag );
$word = substr( $word, 1 );
}
+ // FIXME: Don't use assert()
+ // phpcs:ignore MediaWiki.Usage.ForbiddenFunctions.assert
assert( !strstr( $word, "\n" ) );
$this->group .= $word;
}
*/
use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
/**
* A foreign repository with a remote MediaWiki with an API thingy
* @return bool|string
*/
function getThumbUrlFromCache( $name, $width, $height, $params = "" ) {
- $cache = ObjectCache::getMainWANInstance();
+ $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
// We can't check the local cache using FileRepo functions because
// we override fileExistsBatch(). We have to use the FileBackend directly.
$backend = $this->getBackend(); // convenience
$url = $this->makeUrl( $query, 'api' );
}
- $cache = ObjectCache::getMainWANInstance();
+ $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
return $cache->getWithSetCallback(
$this->getLocalCacheKey( static::class, $target, md5( $url ) ),
$cacheTTL,
* @ingroup FileRepo
*/
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\LoadBalancer;
+
/**
* A foreign repository with a MediaWiki database accessible via the configured LBFactory
*
* @return IDatabase
*/
function getMasterDB() {
- return wfGetLB( $this->wiki )->getConnectionRef( DB_MASTER, [], $this->wiki );
+ return $this->getDBLoadBalancer()->getConnectionRef( DB_MASTER, [], $this->wiki );
}
/**
* @return IDatabase
*/
function getReplicaDB() {
- return wfGetLB( $this->wiki )->getConnectionRef( DB_REPLICA, [], $this->wiki );
+ return $this->getDBLoadBalancer()->getConnectionRef( DB_REPLICA, [], $this->wiki );
}
/**
*/
protected function getDBFactory() {
return function ( $index ) {
- return wfGetLB( $this->wiki )->getConnectionRef( $index, [], $this->wiki );
+ return $this->getDBLoadBalancer()->getConnectionRef( $index, [], $this->wiki );
};
}
+ /**
+ * @return LoadBalancer
+ */
+ protected function getDBLoadBalancer() {
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ return $lbFactory->getMainLB( $this->wiki );
+ }
+
function hasSharedCache() {
return $this->hasSharedCache;
}
* @ingroup FileRepo
*/
+use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\ResultWrapper;
use Wikimedia\Rdbms\Database;
use Wikimedia\Rdbms\IDatabase;
}
$method = __METHOD__;
- $redirDbKey = ObjectCache::getMainWANInstance()->getWithSetCallback(
+ $redirDbKey = MediaWikiServices::getInstance()->getMainWANObjectCache()->getWithSetCallback(
$memcKey,
$expiry,
function ( $oldValue, &$ttl, array &$setOpts ) use ( $method, $title ) {
if ( $key ) {
$this->getMasterDB()->onTransactionPreCommitOrIdle(
function () use ( $key ) {
- ObjectCache::getMainWANInstance()->delete( $key );
+ MediaWikiServices::getInstance()->getMainWANObjectCache()->delete( $key );
},
__METHOD__
);
* @ingroup FileAbstraction
*/
+use MediaWiki\MediaWikiServices;
+
/**
* Class representing a row of the 'filearchive' table
*
'fa_deleted',
'fa_deleted_timestamp', /* Used by LocalFileRestoreBatch */
'fa_sha1',
- ] + CommentStore::getStore()->getFields( 'fa_description' );
+ ] + MediaWikiServices::getInstance()->getCommentStore()->getFields( 'fa_description' );
}
/**
* - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
*/
public static function getQueryInfo() {
- $commentQuery = CommentStore::getStore()->getJoin( 'fa_description' );
+ $commentQuery = MediaWikiServices::getInstance()->getCommentStore()->getJoin( 'fa_description' );
$actorQuery = ActorMigration::newMigration()->getJoin( 'fa_user' );
return [
'tables' => [ 'filearchive' ] + $commentQuery['tables'] + $actorQuery['tables'],
$this->metadata = $row->fa_metadata;
$this->mime = "$row->fa_major_mime/$row->fa_minor_mime";
$this->media_type = $row->fa_media_type;
- $this->description = CommentStore::getStore()
+ $this->description = MediaWikiServices::getInstance()->getCommentStore()
// Legacy because $row may have come from self::selectFields()
->getCommentLegacy( wfGetDB( DB_REPLICA ), 'fa_description', $row )->text;
$this->user = User::newFromAnyId( $row->fa_user, $row->fa_user_text, $row->fa_actor );
$renderUrl = $this->repo->getDescriptionRenderUrl( $this->getName(), $lang->getCode() );
if ( $renderUrl ) {
- $cache = ObjectCache::getMainWANInstance();
+ $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
$key = $this->repo->getLocalCacheKey(
'RemoteFileDescription',
'url',
* @ingroup FileAbstraction
*/
+use MediaWiki\MediaWikiServices;
+
/**
* Foreign file accessible through api.php requests.
* Very hacky and inefficient, do not use :D
/** @var array */
private $mInfo = [];
- protected $repoClass = ForeignApiRepo::class;
+ protected $repoClass = ForeignAPIRepo::class;
/**
* @param Title|string|bool $title
$url = $this->repo->getDescriptionRenderUrl( $this->getName(), $wgContLang->getCode() );
$key = $this->repo->getLocalCacheKey( 'RemoteFileDescription', 'url', md5( $url ) );
- ObjectCache::getMainWANInstance()->delete( $key );
+ MediaWikiServices::getInstance()->getMainWANObjectCache()->delete( $key );
}
/**
*/
function purgeThumbnails( $options = [] ) {
$key = $this->repo->getLocalCacheKey( 'ForeignAPIRepo', 'ThumbUrl', $this->getName() );
- ObjectCache::getMainWANInstance()->delete( $key );
+ MediaWikiServices::getInstance()->getMainWANObjectCache()->delete( $key );
$files = $this->getThumbnails();
// Give media handler a chance to filter the purge list
* @ingroup FileAbstraction
*/
+use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\DBUnexpectedError;
/**
return false; // no description page
}
- $cache = ObjectCache::getMainWANInstance();
+ $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
return $cache->getWithSetCallback(
$this->repo->getLocalCacheKey(
'img_actor' => $wgActorTableSchemaMigrationStage > MIGRATION_OLD ? 'img_actor' : null,
'img_timestamp',
'img_sha1',
- ] + CommentStore::getStore()->getFields( 'img_description' );
+ ] + MediaWikiServices::getInstance()->getCommentStore()->getFields( 'img_description' );
}
/**
* - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
*/
public static function getQueryInfo( array $options = [] ) {
- $commentQuery = CommentStore::getStore()->getJoin( 'img_description' );
+ $commentQuery = MediaWikiServices::getInstance()->getCommentStore()->getJoin( 'img_description' );
$actorQuery = ActorMigration::newMigration()->getJoin( 'img_user' );
$ret = [
'tables' => [ 'image' ] + $commentQuery['tables'] + $actorQuery['tables'],
return;
}
- $cache = ObjectCache::getMainWANInstance();
+ $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
$cachedValues = $cache->getWithSetCallback(
$key,
$cache::TTL_WEEK,
$this->repo->getMasterDB()->onTransactionPreCommitOrIdle(
function () use ( $key ) {
- ObjectCache::getMainWANInstance()->delete( $key );
+ MediaWikiServices::getInstance()->getMainWANObjectCache()->delete( $key );
},
__METHOD__
);
function decodeRow( $row, $prefix = 'img_' ) {
$decoded = $this->unprefixRow( $row, $prefix );
- $decoded['description'] = CommentStore::getStore()
+ $decoded['description'] = MediaWikiServices::getInstance()->getCommentStore()
->getComment( 'description', (object)$decoded )->text;
$decoded['user'] = User::newFromAnyId(
) {
$props = $this->repo->getFileProps( $srcPath );
} else {
- $mwProps = new MWFileProps( MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer() );
+ $mwProps = new MWFileProps( MediaWikiServices::getInstance()->getMimeAnalyzer() );
$props = $mwProps->getPropsFromPath( $srcPath, true );
}
}
# Test to see if the row exists using INSERT IGNORE
# This avoids race conditions by locking the row until the commit, and also
# doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition.
- $commentStore = CommentStore::getStore();
+ $commentStore = MediaWikiServices::getInstance()->getCommentStore();
list( $commentFields, $commentCallback ) =
$commentStore->insertWithTempTable( $dbw, 'img_description', $comment );
$actorMigration = ActorMigration::newMigration();
$now = time();
$dbw = $this->file->repo->getMasterDB();
- $commentStore = CommentStore::getStore();
+ $commentStore = MediaWikiServices::getInstance()->getCommentStore();
$actorMigration = ActorMigration::newMigration();
$encTimestamp = $dbw->addQuotes( $dbw->timestamp( $now ) );
$dbw = $this->file->repo->getMasterDB();
- $commentStore = CommentStore::getStore();
+ $commentStore = MediaWikiServices::getInstance()->getCommentStore();
$actorMigration = ActorMigration::newMigration();
$status = $this->file->repo->newGood();
* @ingroup FileAbstraction
*/
+use MediaWiki\MediaWikiServices;
+
/**
* Class to represent a file in the oldimage table
*
'oi_timestamp',
'oi_deleted',
'oi_sha1',
- ] + CommentStore::getStore()->getFields( 'oi_description' );
+ ] + MediaWikiServices::getInstance()->getCommentStore()->getFields( 'oi_description' );
}
/**
* - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
*/
public static function getQueryInfo( array $options = [] ) {
- $commentQuery = CommentStore::getStore()->getJoin( 'oi_description' );
+ $commentQuery = MediaWikiServices::getInstance()->getCommentStore()->getJoin( 'oi_description' );
$actorQuery = ActorMigration::newMigration()->getJoin( 'oi_user' );
$ret = [
'tables' => [ 'oldimage' ] + $commentQuery['tables'] + $actorQuery['tables'],
return false;
}
- $commentFields = CommentStore::getStore()->insert( $dbw, 'oi_description', $comment );
+ $commentFields = MediaWikiServices::getInstance()->getCommentStore()
+ ->insert( $dbw, 'oi_description', $comment );
$actorFields = ActorMigration::newMigration()->getInsertValues( $dbw, 'oi_user', $user );
$dbw->insert( 'oldimage',
[
* Use whatever the relative field is as the standard HTML input.
*/
public function getInputHTML( $value ) {
- return $this->relativeField->getInputHtml( $value );
+ return $this->relativeField->getInputHTML( $value );
}
protected function shouldInfuseOOUI() {
global $wgStyleDirectory;
$moduleNames = [
- // See SkinTemplate::setupSkinUserCss
+ // Based on Skin::getDefaultModules
'mediawiki.legacy.shared',
- // See Vector::setupSkinUserCss
+ // Based on Vector::setupSkinUserCss
'mediawiki.skinning.interface',
];
"config-apc": "[http://www.php.net/apc APC] instalatuta dago",
"config-apcu": "[http://www.php.net/apcu APCu] instalatuta dago",
"config-wincache": "[https://www.iis.net/download/WinCacheForPhp WinCache] instalatuta dago",
- "config-no-cache-apcu": "<strong>Warning:</strong> Ezin izan da [http://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] edo [http://www.iis.net/download/WinCacheForPhp WinCache] aurkitu.\nObjektu katxea ez dago aktibatuta.",
+ "config-no-cache-apcu": "<strong>Warning:</strong> Ezin izan da [http://www.php.net/apcu APCu] edo [http://www.iis.net/download/WinCacheForPhp WinCache] aurkitu.\nObjektu katxea ez dago aktibatuta.",
"config-mod-security": "<strong>Warning:</strong> Zure web zerbitzariak [https://modsecurity.org/mod_security] / mod_security2 aktibatu du. Honen konfigurazio komun asko sortu ahal dituzte arazoak MediaWikin eta beste software batzuetan, hautazko edukia argitaratzeko aukera ematen dutenei erabiltzaileei.\nAhal izanez gero, desgaitu egin beharko litzateke. Bestela, kontsultatu [https://modsecurity.org/documentation/ mod_security documentation] edo jarri harremanetan zure ostalariarekin ausazko akatsak aurkitzen badituzu.",
"config-diff3-bad": "GNU diff3 ez da aurkitu.",
"config-git": "Git bertsio-kontrol software aurkitu da: <code>$1</code>",
"config-cache-options": "Objektu cachearen ezarpenak:",
"config-cache-help": "Objektuen katxea erabiltzen da MediaWikiko abiadura hobetzeko, sarritan erabiltzen diren datuak gordetzen.\nOso gomendagarria da, webgune handientzako eta ertainentzako, webgune txikiek ere ikusiko dituzte onurak.",
"config-cache-none": "Desaktibatu Katxina (ez dira funtzionaltasunak ezabatu, baina wiki orrialde handietan abiaduran eragina izan ahal du)",
- "config-cache-accel": "PHP objetuen katxea (APC, APCu, XCache edo WinCache)",
+ "config-cache-accel": "PHP objetuen katxea (APC, APCu, edo WinCache)",
"config-cache-memcached": "Memcached erabili (konfigurazio eta instalazio gehiago behar du)",
"config-memcached-servers": "Memcached serbidoreak:",
"config-memcached-help": "Memcached-ekin erabiltzeko IP helbideen lista.\nLerro bakoitzen bat bakarrik jarri behar da eta zehaztu ze ataka erabiliko den. Adibidez:\n127.0.0.1:11211\n192.168.1.25:1234",
"config-nofile": "Ezin da \"$1\" fitxategia aurkitu. Ezabatua izan da?",
"config-extension-link": "Ba al zenekien wikiak [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions extensions] onartzen dituela?\n\nArakatu [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category extensions by category] edo [https://www.mediawiki.org/wiki/Extension_Matrix Extension Matrix] ikusi ahal izateko luzapenen zerrenda.",
"config-skins-screenshots": "$1 (Pantaila-irudia: $2)",
+ "config-extensions-requires": "$1 ($2 behar du)",
"config-screenshot": "Pantaila-irudia",
"mainpagetext": "<strong>MediaWiki instalatu da.</strong>",
"mainpagedocfooter": "Ikusi [https://meta.wikimedia.org/wiki/Help:Contents Erabiltzailearen Gida] wiki softwarea erabiltzen hasteko informazio gehiagorako.\n\n== Nola hasi ==\n\n*\n [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Konfigurazio balioen zerrenda]\n*\n [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ (MediaWikin Maiz egindako galderak)]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWikiren argitalpenen posta zerrenda]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Aurkitu MediaWiki zure hizkuntzan]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Zure wikian spam-a nola borrokatzen ikasi]"
"config-nofile": "Tiedostoa \"$1\" ei löytynyt. Onko se poistettu?",
"config-extension-link": "Tiesitkö että wiki tukee [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions laajennuksia]?\n\nLaajennuksia voi hakea myös [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category luokittain].",
"config-skins-screenshots": "$1 (kuvakaappaukset: $2)",
+ "config-extensions-requires": "$1 (vaatii $2)",
"config-screenshot": "kuvakaappaus",
"mainpagetext": "<strong>MediaWiki on onnistuneesti asennettu.</strong>",
"mainpagedocfooter": "Lisätietoja wiki-ohjelmiston käytöstä on [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents käyttöoppaassa].\n\n=== Aloittaminen ===\n\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Asetusten teko-ohjeita]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWikin FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Sähköpostilista, jolla tiedotetaan MediaWikin uusista versioista]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Käännä MediaWikiä kielellesi]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Katso, kuinka torjua spämmiä wikissäsi]\n\n=== Asetukset ===\n\nTarkista, että alla olevat taivutusmuodot ovat oikein. Jos eivät, tee tarvittavat muutokset tiedostoon LocalSettings.php seuraavasti:\n $wgGrammarForms['fi']['genitive']['{{SITENAME}}'] = '...';\n $wgGrammarForms['fi']['partitive']['{{SITENAME}}'] = '...';\n $wgGrammarForms['fi']['elative']['{{SITENAME}}'] = '...';\n $wgGrammarForms['fi']['inessive']['{{SITENAME}}'] = '...';\n $wgGrammarForms['fi']['illative']['{{SITENAME}}'] = '...';\nTaivutusmuodot: {{GRAMMAR:genitive|{{SITENAME}}}} (yön) – {{GRAMMAR:partitive|{{SITENAME}}}} (yötä) – {{GRAMMAR:elative|{{SITENAME}}}} (yöstä) – {{GRAMMAR:inessive|{{SITENAME}}}} (yössä) – {{GRAMMAR:illative|{{SITENAME}}}} (yöhön)."
"config-nofile": "ファイル「$1」が見つかりませんでした。削除された可能性があります。",
"config-extension-link": "あなたのウィキは[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions 拡張機能]をサポートしていることをご存知ですか?\n\n[https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category カテゴリ別で拡張機能を見る]か[https://www.mediawiki.org/wiki/Extension_Matrix 拡張機能のマトリックス]で拡張機能すべてのリストをご覧になれます。",
"config-skins-screenshots": "$1 (スクリーンショット: $2)",
+ "config-extensions-requires": "$1($2が必要)",
"config-screenshot": "スクリーンショット",
"mainpagetext": "<strong>MediaWiki はインストール済みです。</strong>",
"mainpagedocfooter": "ウィキソフトウェアの使い方に関する情報は[https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents 利用者案内]を参照してください。\n\n== はじめましょう ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings/ja 設定の一覧]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ/ja MediaWiki よくある質問と回答]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki リリース情報メーリングリスト]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation/ja MediaWiki のあなたの言語へのローカライズ]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam あなたのウィキでスパムと戦う方法を学ぶ]"
"config-help": "Hëllef",
"config-help-tooltip": "klickt fir opzeklappen",
"config-nofile": "De Fichier \"$1\" gouf net fonnt. Gouf e geläscht?",
+ "config-extensions-requires": "$1 (brauch $2)",
"config-screenshot": "Screenshot",
"mainpagetext": "<strong>MediaWiki gouf installéiert.</strong>",
"mainpagedocfooter": "Kuckt w.e.g. [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents d'Benotzerhandbuch] fir Informatiounen iwwer de Gebruach vun der Wiki Software.\n\n== Fir unzefänken ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Hëllef bei der Konfiguratioun]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki-FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Mailinglëscht vun neie MediaWiki-Versiounen]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Lokaliséiert MediaWiki fir Är Sprooch]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Léiert wéi Spam op Ärer Wiki reduzéiert gi kann]"
"config-connection-error": "$1.\n\nതാഴെ നൽകിയിരിക്കുന്ന ഹോസ്റ്റ്, ഉപയോക്തൃനാമം, രഹസ്യവാക്ക് എന്നിവ പരിശോധിച്ച് വീണ്ടും ശ്രമിക്കുക.",
"config-regenerate": "LocalSettings.php പുനഃസൃഷ്ടിക്കുക →",
"config-mysql-engine": "സ്റ്റോറേജ് എൻജിൻ:",
+ "config-mysql-utf8": "യു.ടി.എഫ്.-8",
"config-site-name": "വിക്കിയുടെ പേര്:",
"config-site-name-help": "ഇത് ബ്രൗസറിന്റെ ടൈറ്റിൽ ബാറിലും മറ്റനേകം ഇടങ്ങളിലും പ്രദർശിപ്പിക്കപ്പെടും.",
"config-site-name-blank": "സൈറ്റിന്റെ പേര് നൽകുക.",
{
- "@metadata": {
- "authors": [
- "Mark85296341"
- ]
- },
- "mainpagedocfooter": "請參閱[https://meta.wikimedia.org/wiki/Help:Contents 用戶手冊]以獲得使用此 wiki 軟件的訊息!\n\n== 入門 ==\n* [https://www.mediawiki.org/wiki/Manual:Configuration_settings MediaWiki 配置設定清單]\n* [https://www.mediawiki.org/wiki/Manual:FAQ MediaWiki 常見問題解答]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki 發佈郵件清單]"
+ "@metadata": {
+ "authors": [
+ "Mark85296341",
+ "Liuxinyu970226"
+ ]
+ },
+ "config-license-cc-by-sa": "共享創意姓名標示-相同方式分享",
+ "config-license-cc-by": "共享創意姓名標示",
+ "config-cc-not-chosen": "請選擇您要使用的共享創意授權條款,然後點選 \"proceed\"。",
+ "mainpagedocfooter": "請參閱[https://meta.wikimedia.org/wiki/Help:Contents 用戶手冊]以獲得使用此 wiki 軟件的訊息!\n\n== 入門 ==\n* [https://www.mediawiki.org/wiki/Manual:Configuration_settings MediaWiki 配置設定清單]\n* [https://www.mediawiki.org/wiki/Manual:FAQ MediaWiki 常見問題解答]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki 發佈郵件清單]"
}
protected $mAPI;
/** @var string The name of the database (for a connection to be established
- * with wfGetLB( 'wikiid' ))
+ * with LBFactory::getMainLB( 'wikiid' ))
*/
protected $mWikiID;
$store->unlock( $this->key );
} else {
$ok = false;
- $cpIndex = null; // nothing saved
}
if ( !$ok ) {
+ $cpIndex = null; // nothing saved
$bouncedPositions = $this->shutdownPositions;
// Raced out too many times or stash is down
$this->logger->warning( __METHOD__ . ": failed to save master pos for " .
// already be expired and thus treated as non-existing, maintaining correctness.
if ( $this->waitForPosIndex > 0 ) {
$data = null;
+ $indexReached = null; // highest index reached in the position store
$loop = new WaitConditionLoop(
- function () use ( &$data ) {
+ function () use ( &$data, &$indexReached ) {
$data = $this->store->get( $this->key );
if ( !is_array( $data ) ) {
return WaitConditionLoop::CONDITION_CONTINUE; // not found yet
} elseif ( !isset( $data['writeIndex'] ) ) {
return WaitConditionLoop::CONDITION_REACHED; // b/c
}
+ $indexReached = max( $data['writeIndex'], $indexReached );
return ( $data['writeIndex'] >= $this->waitForPosIndex )
? WaitConditionLoop::CONDITION_REACHED
$waitedMs = $loop->getLastWaitTime() * 1e3;
if ( $result == $loop::CONDITION_REACHED ) {
- $msg = "expected and found pos index {$this->waitForPosIndex} ({$waitedMs}ms)";
- $this->logger->debug( $msg );
+ $this->logger->debug(
+ __METHOD__ . ": expected and found position index.",
+ [
+ 'cpPosIndex' => $this->waitForPosIndex,
+ 'waitTimeMs' => $waitedMs
+ ]
+ );
} else {
- $msg = "expected but missed pos index {$this->waitForPosIndex} ({$waitedMs}ms)";
- $this->logger->info( $msg );
+ $this->logger->warning(
+ __METHOD__ . ": expected but failed to find position index.",
+ [
+ 'cpPosIndex' => $this->waitForPosIndex,
+ 'indexReached' => $indexReached,
+ 'waitTimeMs' => $waitedMs
+ ]
+ );
}
} else {
$data = $this->store->get( $this->key );
return $this->__call( __FUNCTION__, func_get_args() );
}
+ public function preCommitCallbacksPending() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
public function writesOrCallbacksPending() {
return $this->__call( __FUNCTION__, func_get_args() );
}
);
}
+ public function preCommitCallbacksPending() {
+ return $this->trxLevel && $this->trxPreCommitCallbacks;
+ }
+
/**
* @return string|null
*/
}
/**
- * Get the list of method names that have pending write queries or callbacks
- * for this transaction
+ * List the methods that have write queries or callbacks for the current transaction
*
- * @return array
+ * This method should not be used outside of Database/LoadBalancer
+ *
+ * @return string[]
+ * @since 1.32
*/
- protected function pendingWriteAndCallbackCallers() {
- if ( !$this->trxLevel ) {
- return [];
- }
-
- $fnames = $this->trxWriteCallers;
+ public function pendingWriteAndCallbackCallers() {
+ $fnames = $this->pendingWriteCallers();
foreach ( [
$this->trxIdleCallbacks,
$this->trxPreCommitCallbacks,
}
// Sanity check that no callbacks are dangling
- if (
- $this->trxIdleCallbacks || $this->trxPreCommitCallbacks || $this->trxEndCallbacks
- ) {
+ $fnames = $this->pendingWriteAndCallbackCallers();
+ if ( $fnames ) {
throw new RuntimeException(
- "Transaction callbacks are still pending:\n" .
- implode( ', ', $this->pendingWriteAndCallbackCallers() )
+ "Transaction callbacks are still pending:\n" . implode( ', ', $fnames )
);
}
}
/**
- * Actually run and consume any "on transaction idle/resolution" callbacks.
+ * Actually consume and run any "on transaction idle/resolution" callbacks.
*
* This method should not be used outside of Database/LoadBalancer
*
* @param int $trigger IDatabase::TRIGGER_* constant
+ * @return int Number of callbacks attempted
* @since 1.20
* @throws Exception
*/
public function runOnTransactionIdleCallbacks( $trigger ) {
+ if ( $this->trxLevel ) { // sanity
+ throw new DBUnexpectedError( $this, __METHOD__ . ': a transaction is still open.' );
+ }
+
if ( $this->trxEndCallbacksSuppressed ) {
- return;
+ return 0;
}
+ $count = 0;
$autoTrx = $this->getFlag( self::DBO_TRX ); // automatic begin() enabled?
/** @var Exception $e */
$e = null; // first exception
$this->trxEndCallbacks = []; // consumed (recursion guard)
foreach ( $callbacks as $callback ) {
try {
+ ++$count;
list( $phpCallback ) = $callback;
$this->clearFlag( self::DBO_TRX ); // make each query its own transaction
call_user_func( $phpCallback, $trigger, $this );
if ( $e instanceof Exception ) {
throw $e; // re-throw any first exception
}
+
+ return $count;
}
/**
- * Actually run and consume any "on transaction pre-commit" callbacks.
+ * Actually consume and run any "on transaction pre-commit" callbacks.
*
* This method should not be used outside of Database/LoadBalancer
*
* @since 1.22
+ * @return int Number of callbacks attempted
* @throws Exception
*/
public function runOnTransactionPreCommitCallbacks() {
+ $count = 0;
+
$e = null; // first exception
do { // callbacks may add callbacks :)
$callbacks = $this->trxPreCommitCallbacks;
$this->trxPreCommitCallbacks = []; // consumed (and recursion guard)
foreach ( $callbacks as $callback ) {
try {
+ ++$count;
list( $phpCallback ) = $callback;
call_user_func( $phpCallback, $this );
} catch ( Exception $ex ) {
if ( $e instanceof Exception ) {
throw $e; // re-throw any first exception
}
+
+ return $count;
}
/**
$savepointId = $cancelable === self::ATOMIC_CANCELABLE ? self::$NOT_APPLICABLE : null;
if ( !$this->trxLevel ) {
- $this->begin( $fname, self::TRANSACTION_INTERNAL );
+ $this->begin( $fname, self::TRANSACTION_INTERNAL ); // sets trxAutomatic
// If DBO_TRX is set, a series of startAtomic/endAtomic pairs will result
// in all changes being in one transaction to keep requests transactional.
if ( $this->getFlag( self::DBO_TRX ) ) {
);
}
- $this->runOnTransactionIdleCallbacks( self::TRIGGER_COMMIT );
- $this->runTransactionListenerCallbacks( self::TRIGGER_COMMIT );
+ // With FLUSHING_ALL_PEERS, callbacks will be explicitly run later
+ if ( $flush !== self::FLUSHING_ALL_PEERS ) {
+ $this->runOnTransactionIdleCallbacks( self::TRIGGER_COMMIT );
+ $this->runTransactionListenerCallbacks( self::TRIGGER_COMMIT );
+ }
}
/**
$this->trxIdleCallbacks = [];
$this->trxPreCommitCallbacks = [];
- if ( $trxActive ) {
+ // With FLUSHING_ALL_PEERS, callbacks will be explicitly run later
+ if ( $trxActive && $flush !== self::FLUSHING_ALL_PEERS ) {
try {
$this->runOnTransactionIdleCallbacks( self::TRIGGER_ROLLBACK );
} catch ( Exception $e ) {
/** @var string Commit/rollback is from the connection manager for the IDatabase handle */
const FLUSHING_ALL_PEERS = 'flush';
/** @var string Commit/rollback is from the IDatabase handle internally */
- const FLUSHING_INTERNAL = 'flush';
+ const FLUSHING_INTERNAL = 'flush-internal';
/** @var string Do not remember the prior flags */
const REMEMBER_NOTHING = '';
public function writesPending();
/**
- * Returns true if there is a transaction/round open with possible write
- * queries or transaction pre-commit/idle callbacks waiting on it to finish.
+ * @return bool Whether there is a transaction open with pre-commit callbacks pending
+ * @since 1.32
+ */
+ public function preCommitCallbacksPending();
+
+ /**
+ * Whether there is a transaction open with either possible write queries
+ * or unresolved pre-commit/commit/resolution callbacks pending
+ *
* This does *not* count recurring callbacks, e.g. from setTransactionListener().
*
* @return bool
* It can also be used for updates that easily suffer from lock timeouts and deadlocks,
* but where atomicity is not essential.
*
+ * Avoid using IDatabase instances aside from this one in the callback, unless such instances
+ * never have IDatabase::DBO_TRX set. This keeps callbacks from interfering with one another.
+ *
* Updates will execute in the order they were enqueued.
*
* @note: do not assume that *other* IDatabase instances will be AUTOCOMMIT mode
* - This IDatabase object
* Callbacks must commit any transactions that they begin.
*
- * Registering a callback here will not affect writesOrCallbacks() pending
+ * Registering a callback here will not affect writesOrCallbacks() pending.
+ *
+ * Since callbacks from this method or onTransactionIdle() can start and end transactions,
+ * a single call to IDatabase::commit might trigger multiple runs of the listener callbacks.
*
* @param string $name Callback name
* @param callable|null $callback Use null to unset a listener
public function rollbackMasterChanges( $fname = __METHOD__ );
/**
- * Check if a transaction round is active
+ * Check if an explicit transaction round is active
* @return bool
* @since 1.29
*/
public function hasTransactionRound();
+ /**
+ * Check if transaction rounds can be started, committed, or rolled back right now
+ *
+ * This can be used as a recusion guard to avoid exceptions in transaction callbacks
+ *
+ * @return bool
+ * @since 1.32
+ */
+ public function isReadyForRoundOperations();
+
/**
* Determine if any master connection has pending changes
* @return bool
/** @var string Agent name for query profiling */
protected $agent;
+ /** @var string One of the ROUND_* class constants */
+ private $trxRoundStage = self::ROUND_CURSORY;
+
+ const ROUND_CURSORY = 'cursory';
+ const ROUND_BEGINNING = 'within-begin';
+ const ROUND_COMMITTING = 'within-commit';
+ const ROUND_ROLLING_BACK = 'within-rollback';
+
private static $loggerFields =
[ 'replLogger', 'connLogger', 'queryLogger', 'perfLogger' ];
$this->forEachLBCallMethod( 'flushReplicaSnapshots', [ $fname ] );
}
- public function commitAll( $fname = __METHOD__, array $options = [] ) {
+ final public function commitAll( $fname = __METHOD__, array $options = [] ) {
$this->commitMasterChanges( $fname, $options );
$this->forEachLBCallMethod( 'commitAll', [ $fname ] );
}
- public function beginMasterChanges( $fname = __METHOD__ ) {
+ final public function beginMasterChanges( $fname = __METHOD__ ) {
+ $this->assertTransactionRoundStage( self::ROUND_CURSORY );
+ $this->trxRoundStage = self::ROUND_BEGINNING;
if ( $this->trxRoundId !== false ) {
throw new DBTransactionError(
null,
$this->trxRoundId = $fname;
// Set DBO_TRX flags on all appropriate DBs
$this->forEachLBCallMethod( 'beginMasterChanges', [ $fname ] );
+ $this->trxRoundStage = self::ROUND_CURSORY;
}
- public function commitMasterChanges( $fname = __METHOD__, array $options = [] ) {
+ final public function commitMasterChanges( $fname = __METHOD__, array $options = [] ) {
+ $this->assertTransactionRoundStage( self::ROUND_CURSORY );
+ $this->trxRoundStage = self::ROUND_COMMITTING;
if ( $this->trxRoundId !== false && $this->trxRoundId !== $fname ) {
throw new DBTransactionError(
null,
/** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForCommit(); // try to ignore client aborts
// Run pre-commit callbacks and suppress post-commit callbacks, aborting on failure
- $this->forEachLBCallMethod( 'finalizeMasterChanges' );
+ do {
+ $count = 0; // number of callbacks executed this iteration
+ $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$count ) {
+ $count += $lb->finalizeMasterChanges();
+ } );
+ } while ( $count > 0 );
$this->trxRoundId = false;
// Perform pre-commit checks, aborting on failure
$this->forEachLBCallMethod( 'approveMasterChanges', [ $options ] );
$this->logIfMultiDbTransaction();
// Actually perform the commit on all master DB connections and revert DBO_TRX
$this->forEachLBCallMethod( 'commitMasterChanges', [ $fname ] );
- // Run all post-commit callbacks
- /** @var Exception $e */
- $e = null; // first callback exception
- $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$e ) {
- $ex = $lb->runMasterPostTrxCallbacks( IDatabase::TRIGGER_COMMIT );
- $e = $e ?: $ex;
- } );
- // Commit any dangling DBO_TRX transactions from callbacks on one DB to another DB
- $this->forEachLBCallMethod( 'commitMasterChanges', [ $fname ] );
+ // Run all post-commit callbacks in a separate step
+ $e = $this->executePostTransactionCallbacks();
+ $this->trxRoundStage = self::ROUND_CURSORY;
// Throw any last post-commit callback error
if ( $e instanceof Exception ) {
throw $e;
}
}
- public function rollbackMasterChanges( $fname = __METHOD__ ) {
+ final public function rollbackMasterChanges( $fname = __METHOD__ ) {
+ $this->trxRoundStage = self::ROUND_ROLLING_BACK;
$this->trxRoundId = false;
- $this->forEachLBCallMethod( 'suppressTransactionEndCallbacks' );
+ // Actually perform the rollback on all master DB connections and revert DBO_TRX
$this->forEachLBCallMethod( 'rollbackMasterChanges', [ $fname ] );
- // Run all post-rollback callbacks
- $this->forEachLB( function ( ILoadBalancer $lb ) {
- $lb->runMasterPostTrxCallbacks( IDatabase::TRIGGER_ROLLBACK );
+ // Run all post-commit callbacks in a separate step
+ $this->executePostTransactionCallbacks();
+ $this->trxRoundStage = self::ROUND_CURSORY;
+ }
+
+ /**
+ * @return Exception|null
+ */
+ private function executePostTransactionCallbacks() {
+ // Run all post-commit callbacks until new ones stop getting added
+ $e = null; // first callback exception
+ do {
+ $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$e ) {
+ $ex = $lb->runMasterTransactionIdleCallbacks();
+ $e = $e ?: $ex;
+ } );
+ } while ( $this->hasMasterChanges() );
+ // Run all listener callbacks once
+ $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$e ) {
+ $ex = $lb->runMasterTransactionListenerCallbacks();
+ $e = $e ?: $ex;
} );
+
+ return $e;
}
public function hasTransactionRound() {
return ( $this->trxRoundId !== false );
}
+ public function isReadyForRoundOperations() {
+ return ( $this->trxRoundStage === self::ROUND_CURSORY );
+ }
+
/**
* Log query info if multi DB transactions are going to be committed now
*/
return $this->ticket;
}
- public function commitAndWaitForReplication( $fname, $ticket, array $opts = [] ) {
+ final public function commitAndWaitForReplication( $fname, $ticket, array $opts = [] ) {
if ( $ticket !== $this->ticket ) {
$this->perfLogger->error( __METHOD__ . ": $fname does not have outer scope.\n" .
( new RuntimeException() )->getTraceAsString() );
$this->requestInfo = $info + $this->requestInfo;
}
+ /**
+ * @param string $stage
+ */
+ private function assertTransactionRoundStage( $stage ) {
+ if ( $this->trxRoundStage !== $stage ) {
+ throw new DBTransactionError(
+ null,
+ "Transaction round stage must be '$stage' (not '{$this->trxRoundStage}')"
+ );
+ }
+ }
+
/**
* Make PHP ignore user aborts/disconnects until the returned
* value leaves scope. This returns null and does nothing in CLI mode.
public function commitAll( $fname = __METHOD__ );
/**
- * Perform all pre-commit callbacks that remain part of the atomic transactions
- * and disable any post-commit callbacks until runMasterPostTrxCallbacks()
+ * Run pre-commit callbacks and defer execution of post-commit callbacks
*
* Use this only for mutli-database commits
+ *
+ * @return int Number of pre-commit callbacks run (since 1.32)
*/
public function finalizeMasterChanges();
public function commitMasterChanges( $fname = __METHOD__ );
/**
- * Issue all pending post-COMMIT/ROLLBACK callbacks
+ * Consume and run all pending post-COMMIT/ROLLBACK callbacks and commit dangling transactions
*
- * Use this only for mutli-database commits
+ * @return Exception|null The first exception or null if there were none
+ */
+ public function runMasterTransactionIdleCallbacks();
+
+ /**
+ * Run all recurring post-COMMIT/ROLLBACK listener callbacks
*
- * @param int $type IDatabase::TRIGGER_* constant
* @return Exception|null The first exception or null if there were none
*/
- public function runMasterPostTrxCallbacks( $type );
+ public function runMasterTransactionListenerCallbacks();
/**
* Issue ROLLBACK only on master, only if queries were done on connection
*/
public function rollbackMasterChanges( $fname = __METHOD__ );
- /**
- * Suppress all pending post-COMMIT/ROLLBACK callbacks
- *
- * Use this only for mutli-database commits
- *
- * @return Exception|null The first exception or null if there were none
- */
- public function suppressTransactionEndCallbacks();
-
/**
* Commit all replica DB transactions so as to flush any REPEATABLE-READ or SSI snapshot
*
public function hasMasterConnection();
/**
- * Determine if there are pending changes in a transaction by this thread
+ * Whether there are pending changes or callbacks in a transaction by this thread
* @return bool
*/
public function hasMasterChanges();
private $connectionAttempted = false;
/** @var int */
private $maxLag = self::MAX_LAG_DEFAULT;
+ /** @var string Stage of the current transaction round in the transaction round life-cycle */
+ private $trxRoundStage = self::ROUND_CURSORY;
/** @var int Warn when this many connection are held */
const CONN_HELD_WARN_THRESHOLD = 10;
const KEY_FOREIGN_FREE_NOROUND = 'foreignFreeAutoCommit';
const KEY_FOREIGN_INUSE_NOROUND = 'foreignInUseAutoCommit';
+ /** @var string Transaction round, explicit or implicit, has not finished writing */
+ const ROUND_CURSORY = 'cursory';
+ /** @var string Transaction round writes are complete and ready for pre-commit checks */
+ const ROUND_FINALIZED = 'finalized';
+ /** @var string Transaction round passed final pre-commit checks */
+ const ROUND_APPROVED = 'approved';
+ /** @var string Transaction round was committed and post-commit callbacks must be run */
+ const ROUND_COMMIT_CALLBACKS = 'commit-callbacks';
+ /** @var string Transaction round was rolled back and post-rollback callbacks must be run */
+ const ROUND_ROLLBACK_CALLBACKS = 'rollback-callbacks';
+ /** @var string Transaction round encountered an error */
+ const ROUND_ERROR = 'error';
+
public function __construct( array $params ) {
if ( !isset( $params['servers'] ) ) {
throw new InvalidArgumentException( __CLASS__ . ': missing servers parameter' );
}
public function commitAll( $fname = __METHOD__ ) {
- $failures = [];
-
- $restore = ( $this->trxRoundId !== false );
- $this->trxRoundId = false;
- $this->forEachOpenConnection(
- function ( IDatabase $conn ) use ( $fname, $restore, &$failures ) {
- try {
- $conn->commit( $fname, $conn::FLUSHING_ALL_PEERS );
- } catch ( DBError $e ) {
- call_user_func( $this->errorLogger, $e );
- $failures[] = "{$conn->getServer()}: {$e->getMessage()}";
- }
- if ( $restore && $conn->getLBInfo( 'master' ) ) {
- $this->undoTransactionRoundFlags( $conn );
- }
- }
- );
-
- if ( $failures ) {
- throw new DBExpectedError(
- null,
- "Commit failed on server(s) " . implode( "\n", array_unique( $failures ) )
- );
- }
+ $this->commitMasterChanges( $fname );
+ $this->flushMasterSnapshots( $fname );
+ $this->flushReplicaSnapshots( $fname );
}
public function finalizeMasterChanges() {
+ $this->assertTransactionRoundStage( [ self::ROUND_CURSORY, self::ROUND_FINALIZED ] );
+
+ $this->trxRoundStage = self::ROUND_ERROR; // "failed" until proven otherwise
+ // Loop until callbacks stop adding callbacks on other connections
+ $total = 0;
+ do {
+ $count = 0; // callbacks execution attempts
+ $this->forEachOpenMasterConnection( function ( Database $conn ) use ( &$count ) {
+ // Run any pre-commit callbacks while leaving the post-commit ones suppressed.
+ // Any error should cause all (peer) transactions to be rolled back together.
+ $count += $conn->runOnTransactionPreCommitCallbacks();
+ } );
+ $total += $count;
+ } while ( $count > 0 );
+ // Defer post-commit callbacks until after COMMIT/ROLLBACK happens on all handles
$this->forEachOpenMasterConnection( function ( Database $conn ) {
- // Any error should cause all DB transactions to be rolled back together
- $conn->setTrxEndCallbackSuppression( false );
- $conn->runOnTransactionPreCommitCallbacks();
- // Defer post-commit callbacks until COMMIT finishes for all DBs
$conn->setTrxEndCallbackSuppression( true );
} );
+ $this->trxRoundStage = self::ROUND_FINALIZED;
+
+ return $total;
}
public function approveMasterChanges( array $options ) {
+ $this->assertTransactionRoundStage( self::ROUND_FINALIZED );
+
$limit = isset( $options['maxWriteDuration'] ) ? $options['maxWriteDuration'] : 0;
+
+ $this->trxRoundStage = self::ROUND_ERROR; // "failed" until proven otherwise
$this->forEachOpenMasterConnection( function ( IDatabase $conn ) use ( $limit ) {
// If atomic sections or explicit transactions are still open, some caller must have
// caught an exception but failed to properly rollback any changes. Detect that and
);
}
} );
+ $this->trxRoundStage = self::ROUND_APPROVED;
}
public function beginMasterChanges( $fname = __METHOD__ ) {
"$fname: Transaction round '{$this->trxRoundId}' already started."
);
}
- $this->trxRoundId = $fname;
+ $this->assertTransactionRoundStage( self::ROUND_CURSORY );
- $failures = [];
- $this->forEachOpenMasterConnection(
- function ( Database $conn ) use ( $fname, &$failures ) {
- $conn->setTrxEndCallbackSuppression( true );
- try {
- $conn->flushSnapshot( $fname );
- } catch ( DBError $e ) {
- call_user_func( $this->errorLogger, $e );
- $failures[] = "{$conn->getServer()}: {$e->getMessage()}";
- }
- $conn->setTrxEndCallbackSuppression( false );
- $this->applyTransactionRoundFlags( $conn );
- }
- );
+ // Clear any empty transactions (no writes/callbacks) from the implicit round
+ $this->flushMasterSnapshots( $fname );
- if ( $failures ) {
- throw new DBExpectedError(
- null,
- "$fname: Flush failed on server(s) " . implode( "\n", array_unique( $failures ) )
- );
- }
+ $this->trxRoundId = $fname;
+ $this->trxRoundStage = self::ROUND_ERROR; // "failed" until proven otherwise
+ // Mark applicable handles as participating in this explicit transaction round.
+ // For each of these handles, any writes and callbacks will be tied to a single
+ // transaction. The (peer) handles will reject begin()/commit() calls unless they
+ // are part of an en masse commit or an en masse rollback.
+ $this->forEachOpenMasterConnection( function ( Database $conn ) {
+ $this->applyTransactionRoundFlags( $conn );
+ } );
+ $this->trxRoundStage = self::ROUND_CURSORY;
}
public function commitMasterChanges( $fname = __METHOD__ ) {
+ $this->assertTransactionRoundStage( self::ROUND_APPROVED );
+
$failures = [];
/** @noinspection PhpUnusedLocalVariableInspection */
$restore = ( $this->trxRoundId !== false );
$this->trxRoundId = false;
+ $this->trxRoundStage = self::ROUND_ERROR; // "failed" until proven otherwise
+ // Commit any writes and clear any snapshots as well (callbacks require AUTOCOMMIT).
+ // Note that callbacks should already be suppressed due to finalizeMasterChanges().
$this->forEachOpenMasterConnection(
- function ( IDatabase $conn ) use ( $fname, $restore, &$failures ) {
+ function ( IDatabase $conn ) use ( $fname, &$failures ) {
try {
- if ( $conn->writesOrCallbacksPending() ) {
- $conn->commit( $fname, $conn::FLUSHING_ALL_PEERS );
- } elseif ( $restore ) {
- $conn->flushSnapshot( $fname );
- }
+ $conn->commit( $fname, $conn::FLUSHING_ALL_PEERS );
} catch ( DBError $e ) {
call_user_func( $this->errorLogger, $e );
$failures[] = "{$conn->getServer()}: {$e->getMessage()}";
}
- if ( $restore ) {
- $this->undoTransactionRoundFlags( $conn );
- }
}
);
-
if ( $failures ) {
- throw new DBExpectedError(
+ throw new DBTransactionError(
null,
"$fname: Commit failed on server(s) " . implode( "\n", array_unique( $failures ) )
);
}
+ if ( $restore ) {
+ // Unmark handles as participating in this explicit transaction round
+ $this->forEachOpenMasterConnection( function ( Database $conn ) {
+ $this->undoTransactionRoundFlags( $conn );
+ } );
+ }
+ $this->trxRoundStage = self::ROUND_COMMIT_CALLBACKS;
}
- public function runMasterPostTrxCallbacks( $type ) {
+ public function runMasterTransactionIdleCallbacks() {
+ if ( $this->trxRoundStage === self::ROUND_COMMIT_CALLBACKS ) {
+ $type = IDatabase::TRIGGER_COMMIT;
+ } elseif ( $this->trxRoundStage === self::ROUND_ROLLBACK_CALLBACKS ) {
+ $type = IDatabase::TRIGGER_ROLLBACK;
+ } else {
+ throw new DBTransactionError(
+ null,
+ "Transaction should be in the callback stage (not '{$this->trxRoundStage}')"
+ );
+ }
+
+ $oldStage = $this->trxRoundStage;
+ $this->trxRoundStage = self::ROUND_ERROR; // "failed" until proven otherwise
+
+ // Now that the COMMIT/ROLLBACK step is over, enable post-commit callback runs
+ $this->forEachOpenMasterConnection( function ( Database $conn ) {
+ $conn->setTrxEndCallbackSuppression( false );
+ } );
+
$e = null; // first exception
+ // Loop until callbacks stop adding callbacks on other connections
+ do {
+ // Run any pending callbacks for each connection...
+ $count = 0; // callback execution attempts
+ $this->forEachOpenMasterConnection(
+ function ( Database $conn ) use ( $type, &$e, &$count ) {
+ if ( $conn->trxLevel() ) {
+ return; // retry in the next iteration, after commit() is called
+ }
+ try {
+ $count += $conn->runOnTransactionIdleCallbacks( $type );
+ } catch ( Exception $ex ) {
+ $e = $e ?: $ex;
+ }
+ }
+ );
+ // Clear out any active transactions left over from callbacks...
+ $this->forEachOpenMasterConnection( function ( Database $conn ) use ( &$e ) {
+ if ( $conn->writesPending() ) {
+ // A callback from another handle wrote to this one and DBO_TRX is set
+ $this->queryLogger->warning( __METHOD__ . ": found writes pending." );
+ $fnames = implode( ', ', $conn->pendingWriteAndCallbackCallers() );
+ $this->queryLogger->warning(
+ __METHOD__ . ": found writes pending ($fnames).",
+ [
+ 'db_server' => $conn->getServer(),
+ 'db_name' => $conn->getDBname()
+ ]
+ );
+ } elseif ( $conn->trxLevel() ) {
+ // A callback from another handle read from this one and DBO_TRX is set,
+ // which can easily happen if there is only one DB (no replicas)
+ $this->queryLogger->debug( __METHOD__ . ": found empty transaction." );
+ }
+ try {
+ $conn->commit( __METHOD__, $conn::FLUSHING_ALL_PEERS );
+ } catch ( Exception $ex ) {
+ $e = $e ?: $ex;
+ }
+ } );
+ } while ( $count > 0 );
+
+ $this->trxRoundStage = $oldStage;
+
+ return $e;
+ }
+
+ public function runMasterTransactionListenerCallbacks() {
+ if ( $this->trxRoundStage === self::ROUND_COMMIT_CALLBACKS ) {
+ $type = IDatabase::TRIGGER_COMMIT;
+ } elseif ( $this->trxRoundStage === self::ROUND_ROLLBACK_CALLBACKS ) {
+ $type = IDatabase::TRIGGER_ROLLBACK;
+ } else {
+ throw new DBTransactionError(
+ null,
+ "Transaction should be in the callback stage (not '{$this->trxRoundStage}')"
+ );
+ }
+
+ $e = null;
+
+ $this->trxRoundStage = self::ROUND_ERROR; // "failed" until proven otherwise
$this->forEachOpenMasterConnection( function ( Database $conn ) use ( $type, &$e ) {
- $conn->setTrxEndCallbackSuppression( false );
- // Callbacks run in AUTO-COMMIT mode, so make sure no transactions are pending...
- if ( $conn->writesPending() ) {
- // This happens if onTransactionIdle() callbacks write to *other* handles
- // (which already finished their callbacks). Let any callbacks run in the final
- // commitMasterChanges() in LBFactory::shutdown(), when the transaction is gone.
- $this->queryLogger->warning( __METHOD__ . ": found writes pending." );
- return;
- } elseif ( $conn->trxLevel() ) {
- // This happens for single-DB setups where DB_REPLICA uses the master DB,
- // thus leaving an implicit read-only transaction open at this point. It
- // also happens if onTransactionIdle() callbacks leave implicit transactions
- // open on *other* DBs (which is slightly improper). Let these COMMIT on the
- // next call to commitMasterChanges(), possibly in LBFactory::shutdown().
- return;
- }
- try {
- $conn->runOnTransactionIdleCallbacks( $type );
- } catch ( Exception $ex ) {
- $e = $e ?: $ex;
- }
try {
$conn->runTransactionListenerCallbacks( $type );
} catch ( Exception $ex ) {
$e = $e ?: $ex;
}
} );
+ $this->trxRoundStage = self::ROUND_CURSORY;
return $e;
}
public function rollbackMasterChanges( $fname = __METHOD__ ) {
$restore = ( $this->trxRoundId !== false );
$this->trxRoundId = false;
- $this->forEachOpenMasterConnection(
- function ( IDatabase $conn ) use ( $fname, $restore ) {
- $conn->rollback( $fname, $conn::FLUSHING_ALL_PEERS );
- if ( $restore ) {
- $this->undoTransactionRoundFlags( $conn );
- }
- }
- );
+ $this->trxRoundStage = self::ROUND_ERROR; // "failed" until proven otherwise
+ $this->forEachOpenMasterConnection( function ( IDatabase $conn ) use ( $fname ) {
+ $conn->rollback( $fname, $conn::FLUSHING_ALL_PEERS );
+ } );
+ if ( $restore ) {
+ // Unmark handles as participating in this explicit transaction round
+ $this->forEachOpenMasterConnection( function ( Database $conn ) {
+ $this->undoTransactionRoundFlags( $conn );
+ } );
+ }
+ $this->trxRoundStage = self::ROUND_ROLLBACK_CALLBACKS;
}
- public function suppressTransactionEndCallbacks() {
- $this->forEachOpenMasterConnection( function ( Database $conn ) {
- $conn->setTrxEndCallbackSuppression( true );
- } );
+ /**
+ * @param string|string[] $stage
+ */
+ private function assertTransactionRoundStage( $stage ) {
+ $stages = (array)$stage;
+
+ if ( !in_array( $this->trxRoundStage, $stages, true ) ) {
+ $stageList = implode(
+ '/',
+ array_map( function ( $v ) {
+ return "'$v'";
+ }, $stages )
+ );
+ throw new DBTransactionError(
+ null,
+ "Transaction round stage must be $stageList (not '{$this->trxRoundStage}')"
+ );
+ }
}
/**
* transaction rounds and remain in auto-commit mode. Such behavior might be desired
* when a DB server is used for something like simple key/value storage.
*
- * @param IDatabase $conn
+ * @param Database $conn
*/
- private function applyTransactionRoundFlags( IDatabase $conn ) {
+ private function applyTransactionRoundFlags( Database $conn ) {
if ( $conn->getLBInfo( 'autoCommitOnly' ) ) {
return; // transaction rounds do not apply to these connections
}
}
/**
- * @param IDatabase $conn
+ * @param Database $conn
*/
- private function undoTransactionRoundFlags( IDatabase $conn ) {
+ private function undoTransactionRoundFlags( Database $conn ) {
if ( $conn->getLBInfo( 'autoCommitOnly' ) ) {
return; // transaction rounds do not apply to these connections
}
}
public function flushReplicaSnapshots( $fname = __METHOD__ ) {
- $this->forEachOpenReplicaConnection( function ( IDatabase $conn ) {
- $conn->flushSnapshot( __METHOD__ );
+ $this->forEachOpenReplicaConnection( function ( IDatabase $conn ) use ( $fname ) {
+ $conn->flushSnapshot( $fname );
} );
}
+ private function flushMasterSnapshots( $fname = __METHOD__ ) {
+ $this->forEachOpenMasterConnection( function ( IDatabase $conn ) use ( $fname ) {
+ $conn->flushSnapshot( $fname );
+ } );
+ }
+
+ /**
+ * @return string
+ * @since 1.32
+ */
+ public function getTransactionRoundStage() {
+ return $this->trxRoundStage;
+ }
+
public function hasMasterConnection() {
return $this->isOpen( $this->getWriterIndex() );
}
}
/**
- * This class wraps around database result row.
+ * A value class to process existing log entries. In other words, this class caches a log
+ * entry from the database and provides an immutable object-oriented representation of it.
*
* @since 1.19
*/
}
}
+/**
+ * A subclass of DatabaseLogEntry for objects constructed from entries in the
+ * recentchanges table (rather than the logging table).
+ */
class RCDatabaseLogEntry extends DatabaseLogEntry {
public function getId() {
}
/**
- * Class for creating log entries manually, to inject them into the database.
+ * Class for creating new log entries and inserting them into the database.
*
* @since 1.19
*/
$tags = [];
}
$rc->addTags( $tags );
- $rc->save( 'pleasedontudp' );
+ $rc->save( $rc::SEND_NONE );
}
if ( $to === 'udp' || $to === 'rcandudp' ) {
*/
private $linkRenderer;
+ /**
+ * @see LogFormatter::getMessageParameters
+ * @var array
+ */
+ protected $parsedParameters;
+
protected function __construct( LogEntry $entry ) {
$this->entry = $entry;
$this->context = RequestContext::getMain();
* @param int|bool $month The month to start from. Default: false
* @param string $tagFilter Tag
* @param string $action Specific action (subtype) requested
+ * @param int $logId Log entry ID, to limit to a single log entry.
*/
public function __construct( $list, $types = [], $performer = '', $title = '',
$pattern = '', $conds = [], $year = false, $month = false, $tagFilter = '',
- $action = ''
+ $action = '', $logId = false
) {
parent::__construct( $list->getContext() );
$this->mConds = $conds;
$this->limitAction( $action );
$this->getDateCond( $year, $month );
$this->mTagFilter = $tagFilter;
+ $this->limitLogId( $logId );
$this->mDb = wfGetDB( DB_REPLICA, 'logpager' );
}
}
}
+ /**
+ * Limit to the (single) specified log ID.
+ * @param int $logId The log entry ID.
+ */
+ protected function limitLogId( $logId ) {
+ if ( !$logId ) {
+ return;
+ }
+ $this->mConds['log_id'] = $logId;
+ }
+
/**
* Constructs the most part of the query. Extra conditions are sprinkled in
* all over this class.
return self::sendInternal( $to, $from, $subject, $body, $options );
}
+ /**
+ * Whether the PEAR Mail_mime library is usable. This will
+ * try and load it if it is not already.
+ *
+ * @return bool
+ */
+ private static function isMailMimeUsable() {
+ static $usable = null;
+ if ( $usable === null ) {
+ // If the class is not already loaded, and it's in the include path,
+ // try requiring it.
+ if ( !class_exists( 'Mail_mime' ) && stream_resolve_include_path( 'Mail/mime.php' ) ) {
+ require_once 'Mail/mime.php';
+ }
+ $usable = class_exists( 'Mail_mime' );
+ }
+
+ return $usable;
+ }
+
+ /**
+ * Whether the PEAR Mail library is usable. This will
+ * try and load it if it is not already.
+ *
+ * @return bool
+ */
+ private static function isMailUsable() {
+ static $usable = null;
+ if ( $usable === null ) {
+ // If the class is not already loaded, and it's in the include path,
+ // try requiring it.
+ if ( !class_exists( 'Mail' ) && stream_resolve_include_path( 'Mail.php' ) ) {
+ require_once 'Mail.php';
+ }
+ $usable = class_exists( 'Mail' );
+ }
+
+ return $usable;
+ }
+
/**
* Helper function fo UserMailer::send() which does the actual sending. It expects a $to
* list which the UserMailerSplitTo hook would not split further.
if ( is_array( $body ) ) {
// we are sending a multipart message
wfDebug( "Assembling multipart mime email\n" );
- if ( !stream_resolve_include_path( 'Mail/mime.php' ) ) {
+ if ( !self::isMailMimeUsable() ) {
wfDebug( "PEAR Mail_Mime package is not installed. Falling back to text email.\n" );
// remove the html body for text email fall back
$body = $body['text'];
} else {
- // Check if pear/mail_mime is already loaded (via composer)
- if ( !class_exists( 'Mail_mime' ) ) {
- require_once 'Mail/mime.php';
- }
+ // pear/mail_mime is already loaded by this point
if ( wfIsWindows() ) {
$body['text'] = str_replace( "\n", "\r\n", $body['text'] );
$body['html'] = str_replace( "\n", "\r\n", $body['html'] );
if ( is_array( $wgSMTP ) ) {
// Check if pear/mail is already loaded (via composer)
- if ( !class_exists( 'Mail' ) ) {
- // PEAR MAILER
- if ( !stream_resolve_include_path( 'Mail.php' ) ) {
- throw new MWException( 'PEAR mail package is not installed' );
- }
- require_once 'Mail.php';
+ if ( !self::isMailUsable() ) {
+ throw new MWException( 'PEAR mail package is not installed' );
}
Wikimedia\suppressWarnings();
+++ /dev/null
-<?php
-/**
- * Handler for Microsoft's bitmap format.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-/**
- * Handler for Microsoft's bitmap format; getimagesize() doesn't
- * support these files
- *
- * @ingroup Media
- */
-class BmpHandler extends BitmapHandler {
- /**
- * @param File $file
- * @return bool
- */
- public function mustRender( $file ) {
- return true;
- }
-
- /**
- * Render files as PNG
- *
- * @param string $text
- * @param string $mime
- * @param array $params
- * @return array
- */
- function getThumbType( $text, $mime, $params = null ) {
- return [ 'png', 'image/png' ];
- }
-
- /**
- * Get width and height from the bmp header.
- *
- * @param File|FSFile $image
- * @param string $filename
- * @return array
- */
- function getImageSize( $image, $filename ) {
- $f = fopen( $filename, 'rb' );
- if ( !$f ) {
- return false;
- }
- $header = fread( $f, 54 );
- fclose( $f );
-
- // Extract binary form of width and height from the header
- $w = substr( $header, 18, 4 );
- $h = substr( $header, 22, 4 );
-
- // Convert the unsigned long 32 bits (little endian):
- try {
- $w = wfUnpack( 'V', $w, 4 );
- $h = wfUnpack( 'V', $h, 4 );
- } catch ( Exception $e ) {
- return false;
- }
-
- return [ $w[1], $h[1] ];
- }
-}
+++ /dev/null
-<?php
-/**
- * Generic handler for bitmap images.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-/**
- * Generic handler for bitmap images
- *
- * @ingroup Media
- */
-class BitmapHandler extends TransformationalImageHandler {
-
- /**
- * Returns which scaler type should be used. Creates parent directories
- * for $dstPath and returns 'client' on error
- *
- * @param string $dstPath
- * @param bool $checkDstPath
- * @return string|Callable One of client, im, custom, gd, imext or an array( object, method )
- */
- protected function getScalerType( $dstPath, $checkDstPath = true ) {
- global $wgUseImageResize, $wgUseImageMagick, $wgCustomConvertCommand;
-
- if ( !$dstPath && $checkDstPath ) {
- # No output path available, client side scaling only
- $scaler = 'client';
- } elseif ( !$wgUseImageResize ) {
- $scaler = 'client';
- } elseif ( $wgUseImageMagick ) {
- $scaler = 'im';
- } elseif ( $wgCustomConvertCommand ) {
- $scaler = 'custom';
- } elseif ( function_exists( 'imagecreatetruecolor' ) ) {
- $scaler = 'gd';
- } elseif ( class_exists( 'Imagick' ) ) {
- $scaler = 'imext';
- } else {
- $scaler = 'client';
- }
-
- return $scaler;
- }
-
- public function makeParamString( $params ) {
- $res = parent::makeParamString( $params );
- if ( isset( $params['interlace'] ) && $params['interlace'] ) {
- return "interlaced-{$res}";
- } else {
- return $res;
- }
- }
-
- public function parseParamString( $str ) {
- $remainder = preg_replace( '/^interlaced-/', '', $str );
- $params = parent::parseParamString( $remainder );
- if ( $params === false ) {
- return false;
- }
- $params['interlace'] = $str !== $remainder;
- return $params;
- }
-
- public function validateParam( $name, $value ) {
- if ( $name === 'interlace' ) {
- return $value === false || $value === true;
- } else {
- return parent::validateParam( $name, $value );
- }
- }
-
- /**
- * @param File $image
- * @param array &$params
- * @return bool
- */
- function normaliseParams( $image, &$params ) {
- global $wgMaxInterlacingAreas;
- if ( !parent::normaliseParams( $image, $params ) ) {
- return false;
- }
- $mimeType = $image->getMimeType();
- $interlace = isset( $params['interlace'] ) && $params['interlace']
- && isset( $wgMaxInterlacingAreas[$mimeType] )
- && $this->getImageArea( $image ) <= $wgMaxInterlacingAreas[$mimeType];
- $params['interlace'] = $interlace;
- return true;
- }
-
- /**
- * Get ImageMagick subsampling factors for the target JPEG pixel format.
- *
- * @param string $pixelFormat one of 'yuv444', 'yuv422', 'yuv420'
- * @return array of string keys
- */
- protected function imageMagickSubsampling( $pixelFormat ) {
- switch ( $pixelFormat ) {
- case 'yuv444':
- return [ '1x1', '1x1', '1x1' ];
- case 'yuv422':
- return [ '2x1', '1x1', '1x1' ];
- case 'yuv420':
- return [ '2x2', '1x1', '1x1' ];
- default:
- throw new MWException( 'Invalid pixel format for JPEG output' );
- }
- }
-
- /**
- * Transform an image using ImageMagick
- *
- * @param File $image File associated with this thumbnail
- * @param array $params Array with scaler params
- *
- * @return MediaTransformError|bool Error object if error occurred, false (=no error) otherwise
- */
- protected function transformImageMagick( $image, $params ) {
- # use ImageMagick
- global $wgSharpenReductionThreshold, $wgSharpenParameter, $wgMaxAnimatedGifArea,
- $wgImageMagickTempDir, $wgImageMagickConvertCommand, $wgJpegPixelFormat,
- $wgJpegQuality;
-
- $quality = [];
- $sharpen = [];
- $scene = false;
- $animation_pre = [];
- $animation_post = [];
- $decoderHint = [];
- $subsampling = [];
-
- if ( $params['mimeType'] == 'image/jpeg' ) {
- $qualityVal = isset( $params['quality'] ) ? (string)$params['quality'] : null;
- $quality = [ '-quality', $qualityVal ?: (string)$wgJpegQuality ]; // 80% by default
- if ( $params['interlace'] ) {
- $animation_post = [ '-interlace', 'JPEG' ];
- }
- # Sharpening, see T8193
- if ( ( $params['physicalWidth'] + $params['physicalHeight'] )
- / ( $params['srcWidth'] + $params['srcHeight'] )
- < $wgSharpenReductionThreshold
- ) {
- $sharpen = [ '-sharpen', $wgSharpenParameter ];
- }
- if ( version_compare( $this->getMagickVersion(), "6.5.6" ) >= 0 ) {
- // JPEG decoder hint to reduce memory, available since IM 6.5.6-2
- $decoderHint = [ '-define', "jpeg:size={$params['physicalDimensions']}" ];
- }
- if ( $wgJpegPixelFormat ) {
- $factors = $this->imageMagickSubsampling( $wgJpegPixelFormat );
- $subsampling = [ '-sampling-factor', implode( ',', $factors ) ];
- }
- } elseif ( $params['mimeType'] == 'image/png' ) {
- $quality = [ '-quality', '95' ]; // zlib 9, adaptive filtering
- if ( $params['interlace'] ) {
- $animation_post = [ '-interlace', 'PNG' ];
- }
- } elseif ( $params['mimeType'] == 'image/webp' ) {
- $quality = [ '-quality', '95' ]; // zlib 9, adaptive filtering
- } elseif ( $params['mimeType'] == 'image/gif' ) {
- if ( $this->getImageArea( $image ) > $wgMaxAnimatedGifArea ) {
- // Extract initial frame only; we're so big it'll
- // be a total drag. :P
- $scene = 0;
- } elseif ( $this->isAnimatedImage( $image ) ) {
- // Coalesce is needed to scale animated GIFs properly (T3017).
- $animation_pre = [ '-coalesce' ];
- // We optimize the output, but -optimize is broken,
- // use optimizeTransparency instead (T13822)
- if ( version_compare( $this->getMagickVersion(), "6.3.5" ) >= 0 ) {
- $animation_post = [ '-fuzz', '5%', '-layers', 'optimizeTransparency' ];
- }
- }
- if ( $params['interlace'] && version_compare( $this->getMagickVersion(), "6.3.4" ) >= 0
- && !$this->isAnimatedImage( $image ) ) { // interlacing animated GIFs is a bad idea
- $animation_post[] = '-interlace';
- $animation_post[] = 'GIF';
- }
- } elseif ( $params['mimeType'] == 'image/x-xcf' ) {
- // Before merging layers, we need to set the background
- // to be transparent to preserve alpha, as -layers merge
- // merges all layers on to a canvas filled with the
- // background colour. After merging we reset the background
- // to be white for the default background colour setting
- // in the PNG image (which is used in old IE)
- $animation_pre = [
- '-background', 'transparent',
- '-layers', 'merge',
- '-background', 'white',
- ];
- Wikimedia\suppressWarnings();
- $xcfMeta = unserialize( $image->getMetadata() );
- Wikimedia\restoreWarnings();
- if ( $xcfMeta
- && isset( $xcfMeta['colorType'] )
- && $xcfMeta['colorType'] === 'greyscale-alpha'
- && version_compare( $this->getMagickVersion(), "6.8.9-3" ) < 0
- ) {
- // T68323 - Greyscale images not rendered properly.
- // So only take the "red" channel.
- $channelOnly = [ '-channel', 'R', '-separate' ];
- $animation_pre = array_merge( $animation_pre, $channelOnly );
- }
- }
-
- // Use one thread only, to avoid deadlock bugs on OOM
- $env = [ 'OMP_NUM_THREADS' => 1 ];
- if ( strval( $wgImageMagickTempDir ) !== '' ) {
- $env['MAGICK_TMPDIR'] = $wgImageMagickTempDir;
- }
-
- $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image );
- list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
-
- $cmd = call_user_func_array( 'wfEscapeShellArg', array_merge(
- [ $wgImageMagickConvertCommand ],
- $quality,
- // Specify white background color, will be used for transparent images
- // in Internet Explorer/Windows instead of default black.
- [ '-background', 'white' ],
- $decoderHint,
- [ $this->escapeMagickInput( $params['srcPath'], $scene ) ],
- $animation_pre,
- // For the -thumbnail option a "!" is needed to force exact size,
- // or ImageMagick may decide your ratio is wrong and slice off
- // a pixel.
- [ '-thumbnail', "{$width}x{$height}!" ],
- // Add the source url as a comment to the thumb, but don't add the flag if there's no comment
- ( $params['comment'] !== ''
- ? [ '-set', 'comment', $this->escapeMagickProperty( $params['comment'] ) ]
- : [] ),
- // T108616: Avoid exposure of local file path
- [ '+set', 'Thumb::URI' ],
- [ '-depth', 8 ],
- $sharpen,
- [ '-rotate', "-$rotation" ],
- $subsampling,
- $animation_post,
- [ $this->escapeMagickOutput( $params['dstPath'] ) ] ) );
-
- wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
- $retval = 0;
- $err = wfShellExecWithStderr( $cmd, $retval, $env );
-
- if ( $retval !== 0 ) {
- $this->logErrorForExternalProcess( $retval, $err, $cmd );
-
- return $this->getMediaTransformError( $params, "$err\nError code: $retval" );
- }
-
- return false; # No error
- }
-
- /**
- * Transform an image using the Imagick PHP extension
- *
- * @param File $image File associated with this thumbnail
- * @param array $params Array with scaler params
- *
- * @return MediaTransformError Error|bool object if error occurred, false (=no error) otherwise
- */
- protected function transformImageMagickExt( $image, $params ) {
- global $wgSharpenReductionThreshold, $wgSharpenParameter, $wgMaxAnimatedGifArea,
- $wgJpegPixelFormat, $wgJpegQuality;
-
- try {
- $im = new Imagick();
- $im->readImage( $params['srcPath'] );
-
- if ( $params['mimeType'] == 'image/jpeg' ) {
- // Sharpening, see T8193
- if ( ( $params['physicalWidth'] + $params['physicalHeight'] )
- / ( $params['srcWidth'] + $params['srcHeight'] )
- < $wgSharpenReductionThreshold
- ) {
- // Hack, since $wgSharpenParameter is written specifically for the command line convert
- list( $radius, $sigma ) = explode( 'x', $wgSharpenParameter );
- $im->sharpenImage( $radius, $sigma );
- }
- $qualityVal = isset( $params['quality'] ) ? (string)$params['quality'] : null;
- $im->setCompressionQuality( $qualityVal ?: $wgJpegQuality );
- if ( $params['interlace'] ) {
- $im->setInterlaceScheme( Imagick::INTERLACE_JPEG );
- }
- if ( $wgJpegPixelFormat ) {
- $factors = $this->imageMagickSubsampling( $wgJpegPixelFormat );
- $im->setSamplingFactors( $factors );
- }
- } elseif ( $params['mimeType'] == 'image/png' ) {
- $im->setCompressionQuality( 95 );
- if ( $params['interlace'] ) {
- $im->setInterlaceScheme( Imagick::INTERLACE_PNG );
- }
- } elseif ( $params['mimeType'] == 'image/gif' ) {
- if ( $this->getImageArea( $image ) > $wgMaxAnimatedGifArea ) {
- // Extract initial frame only; we're so big it'll
- // be a total drag. :P
- $im->setImageScene( 0 );
- } elseif ( $this->isAnimatedImage( $image ) ) {
- // Coalesce is needed to scale animated GIFs properly (T3017).
- $im = $im->coalesceImages();
- }
- // GIF interlacing is only available since 6.3.4
- $v = Imagick::getVersion();
- preg_match( '/ImageMagick ([0-9]+\.[0-9]+\.[0-9]+)/', $v['versionString'], $v );
-
- if ( $params['interlace'] && version_compare( $v[1], '6.3.4' ) >= 0 ) {
- $im->setInterlaceScheme( Imagick::INTERLACE_GIF );
- }
- }
-
- $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image );
- list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
-
- $im->setImageBackgroundColor( new ImagickPixel( 'white' ) );
-
- // Call Imagick::thumbnailImage on each frame
- foreach ( $im as $i => $frame ) {
- if ( !$frame->thumbnailImage( $width, $height, /* fit */ false ) ) {
- return $this->getMediaTransformError( $params, "Error scaling frame $i" );
- }
- }
- $im->setImageDepth( 8 );
-
- if ( $rotation ) {
- if ( !$im->rotateImage( new ImagickPixel( 'white' ), 360 - $rotation ) ) {
- return $this->getMediaTransformError( $params, "Error rotating $rotation degrees" );
- }
- }
-
- if ( $this->isAnimatedImage( $image ) ) {
- wfDebug( __METHOD__ . ": Writing animated thumbnail\n" );
- // This is broken somehow... can't find out how to fix it
- $result = $im->writeImages( $params['dstPath'], true );
- } else {
- $result = $im->writeImage( $params['dstPath'] );
- }
- if ( !$result ) {
- return $this->getMediaTransformError( $params,
- "Unable to write thumbnail to {$params['dstPath']}" );
- }
- } catch ( ImagickException $e ) {
- return $this->getMediaTransformError( $params, $e->getMessage() );
- }
-
- return false;
- }
-
- /**
- * Transform an image using a custom command
- *
- * @param File $image File associated with this thumbnail
- * @param array $params Array with scaler params
- *
- * @return MediaTransformError Error|bool object if error occurred, false (=no error) otherwise
- */
- protected function transformCustom( $image, $params ) {
- # Use a custom convert command
- global $wgCustomConvertCommand;
-
- # Variables: %s %d %w %h
- $src = wfEscapeShellArg( $params['srcPath'] );
- $dst = wfEscapeShellArg( $params['dstPath'] );
- $cmd = $wgCustomConvertCommand;
- $cmd = str_replace( '%s', $src, str_replace( '%d', $dst, $cmd ) ); # Filenames
- $cmd = str_replace( '%h', wfEscapeShellArg( $params['physicalHeight'] ),
- str_replace( '%w', wfEscapeShellArg( $params['physicalWidth'] ), $cmd ) ); # Size
- wfDebug( __METHOD__ . ": Running custom convert command $cmd\n" );
- $retval = 0;
- $err = wfShellExecWithStderr( $cmd, $retval );
-
- if ( $retval !== 0 ) {
- $this->logErrorForExternalProcess( $retval, $err, $cmd );
-
- return $this->getMediaTransformError( $params, $err );
- }
-
- return false; # No error
- }
-
- /**
- * Transform an image using the built in GD library
- *
- * @param File $image File associated with this thumbnail
- * @param array $params Array with scaler params
- *
- * @return MediaTransformError|bool Error object if error occurred, false (=no error) otherwise
- */
- protected function transformGd( $image, $params ) {
- # Use PHP's builtin GD library functions.
- # First find out what kind of file this is, and select the correct
- # input routine for this.
-
- $typemap = [
- 'image/gif' => [ 'imagecreatefromgif', 'palette', false, 'imagegif' ],
- 'image/jpeg' => [ 'imagecreatefromjpeg', 'truecolor', true,
- [ __CLASS__, 'imageJpegWrapper' ] ],
- 'image/png' => [ 'imagecreatefrompng', 'bits', false, 'imagepng' ],
- 'image/vnd.wap.wbmp' => [ 'imagecreatefromwbmp', 'palette', false, 'imagewbmp' ],
- 'image/xbm' => [ 'imagecreatefromxbm', 'palette', false, 'imagexbm' ],
- ];
-
- if ( !isset( $typemap[$params['mimeType']] ) ) {
- $err = 'Image type not supported';
- wfDebug( "$err\n" );
- $errMsg = wfMessage( 'thumbnail_image-type' )->text();
-
- return $this->getMediaTransformError( $params, $errMsg );
- }
- list( $loader, $colorStyle, $useQuality, $saveType ) = $typemap[$params['mimeType']];
-
- if ( !function_exists( $loader ) ) {
- $err = "Incomplete GD library configuration: missing function $loader";
- wfDebug( "$err\n" );
- $errMsg = wfMessage( 'thumbnail_gd-library', $loader )->text();
-
- return $this->getMediaTransformError( $params, $errMsg );
- }
-
- if ( !file_exists( $params['srcPath'] ) ) {
- $err = "File seems to be missing: {$params['srcPath']}";
- wfDebug( "$err\n" );
- $errMsg = wfMessage( 'thumbnail_image-missing', $params['srcPath'] )->text();
-
- return $this->getMediaTransformError( $params, $errMsg );
- }
-
- if ( filesize( $params['srcPath'] ) === 0 ) {
- $err = "Image file size seems to be zero.";
- wfDebug( "$err\n" );
- $errMsg = wfMessage( 'thumbnail_image-size-zero', $params['srcPath'] )->text();
-
- return $this->getMediaTransformError( $params, $errMsg );
- }
-
- $src_image = call_user_func( $loader, $params['srcPath'] );
-
- $rotation = function_exists( 'imagerotate' ) && !isset( $params['disableRotation'] ) ?
- $this->getRotation( $image ) :
- 0;
- list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
- $dst_image = imagecreatetruecolor( $width, $height );
-
- // Initialise the destination image to transparent instead of
- // the default solid black, to support PNG and GIF transparency nicely
- $background = imagecolorallocate( $dst_image, 0, 0, 0 );
- imagecolortransparent( $dst_image, $background );
- imagealphablending( $dst_image, false );
-
- if ( $colorStyle == 'palette' ) {
- // Don't resample for paletted GIF images.
- // It may just uglify them, and completely breaks transparency.
- imagecopyresized( $dst_image, $src_image,
- 0, 0, 0, 0,
- $width, $height,
- imagesx( $src_image ), imagesy( $src_image ) );
- } else {
- imagecopyresampled( $dst_image, $src_image,
- 0, 0, 0, 0,
- $width, $height,
- imagesx( $src_image ), imagesy( $src_image ) );
- }
-
- if ( $rotation % 360 != 0 && $rotation % 90 == 0 ) {
- $rot_image = imagerotate( $dst_image, $rotation, 0 );
- imagedestroy( $dst_image );
- $dst_image = $rot_image;
- }
-
- imagesavealpha( $dst_image, true );
-
- $funcParams = [ $dst_image, $params['dstPath'] ];
- if ( $useQuality && isset( $params['quality'] ) ) {
- $funcParams[] = $params['quality'];
- }
- call_user_func_array( $saveType, $funcParams );
-
- imagedestroy( $dst_image );
- imagedestroy( $src_image );
-
- return false; # No error
- }
-
- /**
- * Callback for transformGd when transforming jpeg images.
- *
- * @param resource $dst_image Image resource of the original image
- * @param string $thumbPath File path to write the thumbnail image to
- * @param int|null $quality Quality of the thumbnail from 1-100,
- * or null to use default quality.
- */
- static function imageJpegWrapper( $dst_image, $thumbPath, $quality = null ) {
- global $wgJpegQuality;
-
- if ( $quality === null ) {
- $quality = $wgJpegQuality;
- }
-
- imageinterlace( $dst_image );
- imagejpeg( $dst_image, $thumbPath, $quality );
- }
-
- /**
- * Returns whether the current scaler supports rotation (im and gd do)
- *
- * @return bool
- */
- public function canRotate() {
- $scaler = $this->getScalerType( null, false );
- switch ( $scaler ) {
- case 'im':
- # ImageMagick supports autorotation
- return true;
- case 'imext':
- # Imagick::rotateImage
- return true;
- case 'gd':
- # GD's imagerotate function is used to rotate images, but not
- # all precompiled PHP versions have that function
- return function_exists( 'imagerotate' );
- default:
- # Other scalers don't support rotation
- return false;
- }
- }
-
- /**
- * @see $wgEnableAutoRotation
- * @return bool Whether auto rotation is enabled
- */
- public function autoRotateEnabled() {
- global $wgEnableAutoRotation;
-
- if ( $wgEnableAutoRotation === null ) {
- // Only enable auto-rotation when we actually can
- return $this->canRotate();
- }
-
- return $wgEnableAutoRotation;
- }
-
- /**
- * @param File $file
- * @param array $params Rotate parameters.
- * 'rotation' clockwise rotation in degrees, allowed are multiples of 90
- * @since 1.21
- * @return bool|MediaTransformError
- */
- public function rotate( $file, $params ) {
- global $wgImageMagickConvertCommand;
-
- $rotation = ( $params['rotation'] + $this->getRotation( $file ) ) % 360;
- $scene = false;
-
- $scaler = $this->getScalerType( null, false );
- switch ( $scaler ) {
- case 'im':
- $cmd = wfEscapeShellArg( $wgImageMagickConvertCommand ) . " " .
- wfEscapeShellArg( $this->escapeMagickInput( $params['srcPath'], $scene ) ) .
- " -rotate " . wfEscapeShellArg( "-$rotation" ) . " " .
- wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) );
- wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
- $retval = 0;
- $err = wfShellExecWithStderr( $cmd, $retval );
- if ( $retval !== 0 ) {
- $this->logErrorForExternalProcess( $retval, $err, $cmd );
-
- return new MediaTransformError( 'thumbnail_error', 0, 0, $err );
- }
-
- return false;
- case 'imext':
- $im = new Imagick();
- $im->readImage( $params['srcPath'] );
- if ( !$im->rotateImage( new ImagickPixel( 'white' ), 360 - $rotation ) ) {
- return new MediaTransformError( 'thumbnail_error', 0, 0,
- "Error rotating $rotation degrees" );
- }
- $result = $im->writeImage( $params['dstPath'] );
- if ( !$result ) {
- return new MediaTransformError( 'thumbnail_error', 0, 0,
- "Unable to write image to {$params['dstPath']}" );
- }
-
- return false;
- default:
- return new MediaTransformError( 'thumbnail_error', 0, 0,
- "$scaler rotation not implemented" );
- }
- }
-}
--- /dev/null
+<?php
+/**
+ * Generic handler for bitmap images.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * Generic handler for bitmap images
+ *
+ * @ingroup Media
+ */
+class BitmapHandler extends TransformationalImageHandler {
+
+ /**
+ * Returns which scaler type should be used. Creates parent directories
+ * for $dstPath and returns 'client' on error
+ *
+ * @param string $dstPath
+ * @param bool $checkDstPath
+ * @return string|Callable One of client, im, custom, gd, imext or an array( object, method )
+ */
+ protected function getScalerType( $dstPath, $checkDstPath = true ) {
+ global $wgUseImageResize, $wgUseImageMagick, $wgCustomConvertCommand;
+
+ if ( !$dstPath && $checkDstPath ) {
+ # No output path available, client side scaling only
+ $scaler = 'client';
+ } elseif ( !$wgUseImageResize ) {
+ $scaler = 'client';
+ } elseif ( $wgUseImageMagick ) {
+ $scaler = 'im';
+ } elseif ( $wgCustomConvertCommand ) {
+ $scaler = 'custom';
+ } elseif ( function_exists( 'imagecreatetruecolor' ) ) {
+ $scaler = 'gd';
+ } elseif ( class_exists( 'Imagick' ) ) {
+ $scaler = 'imext';
+ } else {
+ $scaler = 'client';
+ }
+
+ return $scaler;
+ }
+
+ public function makeParamString( $params ) {
+ $res = parent::makeParamString( $params );
+ if ( isset( $params['interlace'] ) && $params['interlace'] ) {
+ return "interlaced-{$res}";
+ } else {
+ return $res;
+ }
+ }
+
+ public function parseParamString( $str ) {
+ $remainder = preg_replace( '/^interlaced-/', '', $str );
+ $params = parent::parseParamString( $remainder );
+ if ( $params === false ) {
+ return false;
+ }
+ $params['interlace'] = $str !== $remainder;
+ return $params;
+ }
+
+ public function validateParam( $name, $value ) {
+ if ( $name === 'interlace' ) {
+ return $value === false || $value === true;
+ } else {
+ return parent::validateParam( $name, $value );
+ }
+ }
+
+ /**
+ * @param File $image
+ * @param array &$params
+ * @return bool
+ */
+ function normaliseParams( $image, &$params ) {
+ global $wgMaxInterlacingAreas;
+ if ( !parent::normaliseParams( $image, $params ) ) {
+ return false;
+ }
+ $mimeType = $image->getMimeType();
+ $interlace = isset( $params['interlace'] ) && $params['interlace']
+ && isset( $wgMaxInterlacingAreas[$mimeType] )
+ && $this->getImageArea( $image ) <= $wgMaxInterlacingAreas[$mimeType];
+ $params['interlace'] = $interlace;
+ return true;
+ }
+
+ /**
+ * Get ImageMagick subsampling factors for the target JPEG pixel format.
+ *
+ * @param string $pixelFormat one of 'yuv444', 'yuv422', 'yuv420'
+ * @return array of string keys
+ */
+ protected function imageMagickSubsampling( $pixelFormat ) {
+ switch ( $pixelFormat ) {
+ case 'yuv444':
+ return [ '1x1', '1x1', '1x1' ];
+ case 'yuv422':
+ return [ '2x1', '1x1', '1x1' ];
+ case 'yuv420':
+ return [ '2x2', '1x1', '1x1' ];
+ default:
+ throw new MWException( 'Invalid pixel format for JPEG output' );
+ }
+ }
+
+ /**
+ * Transform an image using ImageMagick
+ *
+ * @param File $image File associated with this thumbnail
+ * @param array $params Array with scaler params
+ *
+ * @return MediaTransformError|bool Error object if error occurred, false (=no error) otherwise
+ */
+ protected function transformImageMagick( $image, $params ) {
+ # use ImageMagick
+ global $wgSharpenReductionThreshold, $wgSharpenParameter, $wgMaxAnimatedGifArea,
+ $wgImageMagickTempDir, $wgImageMagickConvertCommand, $wgJpegPixelFormat,
+ $wgJpegQuality;
+
+ $quality = [];
+ $sharpen = [];
+ $scene = false;
+ $animation_pre = [];
+ $animation_post = [];
+ $decoderHint = [];
+ $subsampling = [];
+
+ if ( $params['mimeType'] == 'image/jpeg' ) {
+ $qualityVal = isset( $params['quality'] ) ? (string)$params['quality'] : null;
+ $quality = [ '-quality', $qualityVal ?: (string)$wgJpegQuality ]; // 80% by default
+ if ( $params['interlace'] ) {
+ $animation_post = [ '-interlace', 'JPEG' ];
+ }
+ # Sharpening, see T8193
+ if ( ( $params['physicalWidth'] + $params['physicalHeight'] )
+ / ( $params['srcWidth'] + $params['srcHeight'] )
+ < $wgSharpenReductionThreshold
+ ) {
+ $sharpen = [ '-sharpen', $wgSharpenParameter ];
+ }
+ if ( version_compare( $this->getMagickVersion(), "6.5.6" ) >= 0 ) {
+ // JPEG decoder hint to reduce memory, available since IM 6.5.6-2
+ $decoderHint = [ '-define', "jpeg:size={$params['physicalDimensions']}" ];
+ }
+ if ( $wgJpegPixelFormat ) {
+ $factors = $this->imageMagickSubsampling( $wgJpegPixelFormat );
+ $subsampling = [ '-sampling-factor', implode( ',', $factors ) ];
+ }
+ } elseif ( $params['mimeType'] == 'image/png' ) {
+ $quality = [ '-quality', '95' ]; // zlib 9, adaptive filtering
+ if ( $params['interlace'] ) {
+ $animation_post = [ '-interlace', 'PNG' ];
+ }
+ } elseif ( $params['mimeType'] == 'image/webp' ) {
+ $quality = [ '-quality', '95' ]; // zlib 9, adaptive filtering
+ } elseif ( $params['mimeType'] == 'image/gif' ) {
+ if ( $this->getImageArea( $image ) > $wgMaxAnimatedGifArea ) {
+ // Extract initial frame only; we're so big it'll
+ // be a total drag. :P
+ $scene = 0;
+ } elseif ( $this->isAnimatedImage( $image ) ) {
+ // Coalesce is needed to scale animated GIFs properly (T3017).
+ $animation_pre = [ '-coalesce' ];
+ // We optimize the output, but -optimize is broken,
+ // use optimizeTransparency instead (T13822)
+ if ( version_compare( $this->getMagickVersion(), "6.3.5" ) >= 0 ) {
+ $animation_post = [ '-fuzz', '5%', '-layers', 'optimizeTransparency' ];
+ }
+ }
+ if ( $params['interlace'] && version_compare( $this->getMagickVersion(), "6.3.4" ) >= 0
+ && !$this->isAnimatedImage( $image ) ) { // interlacing animated GIFs is a bad idea
+ $animation_post[] = '-interlace';
+ $animation_post[] = 'GIF';
+ }
+ } elseif ( $params['mimeType'] == 'image/x-xcf' ) {
+ // Before merging layers, we need to set the background
+ // to be transparent to preserve alpha, as -layers merge
+ // merges all layers on to a canvas filled with the
+ // background colour. After merging we reset the background
+ // to be white for the default background colour setting
+ // in the PNG image (which is used in old IE)
+ $animation_pre = [
+ '-background', 'transparent',
+ '-layers', 'merge',
+ '-background', 'white',
+ ];
+ Wikimedia\suppressWarnings();
+ $xcfMeta = unserialize( $image->getMetadata() );
+ Wikimedia\restoreWarnings();
+ if ( $xcfMeta
+ && isset( $xcfMeta['colorType'] )
+ && $xcfMeta['colorType'] === 'greyscale-alpha'
+ && version_compare( $this->getMagickVersion(), "6.8.9-3" ) < 0
+ ) {
+ // T68323 - Greyscale images not rendered properly.
+ // So only take the "red" channel.
+ $channelOnly = [ '-channel', 'R', '-separate' ];
+ $animation_pre = array_merge( $animation_pre, $channelOnly );
+ }
+ }
+
+ // Use one thread only, to avoid deadlock bugs on OOM
+ $env = [ 'OMP_NUM_THREADS' => 1 ];
+ if ( strval( $wgImageMagickTempDir ) !== '' ) {
+ $env['MAGICK_TMPDIR'] = $wgImageMagickTempDir;
+ }
+
+ $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image );
+ list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
+
+ $cmd = call_user_func_array( 'wfEscapeShellArg', array_merge(
+ [ $wgImageMagickConvertCommand ],
+ $quality,
+ // Specify white background color, will be used for transparent images
+ // in Internet Explorer/Windows instead of default black.
+ [ '-background', 'white' ],
+ $decoderHint,
+ [ $this->escapeMagickInput( $params['srcPath'], $scene ) ],
+ $animation_pre,
+ // For the -thumbnail option a "!" is needed to force exact size,
+ // or ImageMagick may decide your ratio is wrong and slice off
+ // a pixel.
+ [ '-thumbnail', "{$width}x{$height}!" ],
+ // Add the source url as a comment to the thumb, but don't add the flag if there's no comment
+ ( $params['comment'] !== ''
+ ? [ '-set', 'comment', $this->escapeMagickProperty( $params['comment'] ) ]
+ : [] ),
+ // T108616: Avoid exposure of local file path
+ [ '+set', 'Thumb::URI' ],
+ [ '-depth', 8 ],
+ $sharpen,
+ [ '-rotate', "-$rotation" ],
+ $subsampling,
+ $animation_post,
+ [ $this->escapeMagickOutput( $params['dstPath'] ) ] ) );
+
+ wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
+ $retval = 0;
+ $err = wfShellExecWithStderr( $cmd, $retval, $env );
+
+ if ( $retval !== 0 ) {
+ $this->logErrorForExternalProcess( $retval, $err, $cmd );
+
+ return $this->getMediaTransformError( $params, "$err\nError code: $retval" );
+ }
+
+ return false; # No error
+ }
+
+ /**
+ * Transform an image using the Imagick PHP extension
+ *
+ * @param File $image File associated with this thumbnail
+ * @param array $params Array with scaler params
+ *
+ * @return MediaTransformError Error|bool object if error occurred, false (=no error) otherwise
+ */
+ protected function transformImageMagickExt( $image, $params ) {
+ global $wgSharpenReductionThreshold, $wgSharpenParameter, $wgMaxAnimatedGifArea,
+ $wgJpegPixelFormat, $wgJpegQuality;
+
+ try {
+ $im = new Imagick();
+ $im->readImage( $params['srcPath'] );
+
+ if ( $params['mimeType'] == 'image/jpeg' ) {
+ // Sharpening, see T8193
+ if ( ( $params['physicalWidth'] + $params['physicalHeight'] )
+ / ( $params['srcWidth'] + $params['srcHeight'] )
+ < $wgSharpenReductionThreshold
+ ) {
+ // Hack, since $wgSharpenParameter is written specifically for the command line convert
+ list( $radius, $sigma ) = explode( 'x', $wgSharpenParameter );
+ $im->sharpenImage( $radius, $sigma );
+ }
+ $qualityVal = isset( $params['quality'] ) ? (string)$params['quality'] : null;
+ $im->setCompressionQuality( $qualityVal ?: $wgJpegQuality );
+ if ( $params['interlace'] ) {
+ $im->setInterlaceScheme( Imagick::INTERLACE_JPEG );
+ }
+ if ( $wgJpegPixelFormat ) {
+ $factors = $this->imageMagickSubsampling( $wgJpegPixelFormat );
+ $im->setSamplingFactors( $factors );
+ }
+ } elseif ( $params['mimeType'] == 'image/png' ) {
+ $im->setCompressionQuality( 95 );
+ if ( $params['interlace'] ) {
+ $im->setInterlaceScheme( Imagick::INTERLACE_PNG );
+ }
+ } elseif ( $params['mimeType'] == 'image/gif' ) {
+ if ( $this->getImageArea( $image ) > $wgMaxAnimatedGifArea ) {
+ // Extract initial frame only; we're so big it'll
+ // be a total drag. :P
+ $im->setImageScene( 0 );
+ } elseif ( $this->isAnimatedImage( $image ) ) {
+ // Coalesce is needed to scale animated GIFs properly (T3017).
+ $im = $im->coalesceImages();
+ }
+ // GIF interlacing is only available since 6.3.4
+ $v = Imagick::getVersion();
+ preg_match( '/ImageMagick ([0-9]+\.[0-9]+\.[0-9]+)/', $v['versionString'], $v );
+
+ if ( $params['interlace'] && version_compare( $v[1], '6.3.4' ) >= 0 ) {
+ $im->setInterlaceScheme( Imagick::INTERLACE_GIF );
+ }
+ }
+
+ $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image );
+ list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
+
+ $im->setImageBackgroundColor( new ImagickPixel( 'white' ) );
+
+ // Call Imagick::thumbnailImage on each frame
+ foreach ( $im as $i => $frame ) {
+ if ( !$frame->thumbnailImage( $width, $height, /* fit */ false ) ) {
+ return $this->getMediaTransformError( $params, "Error scaling frame $i" );
+ }
+ }
+ $im->setImageDepth( 8 );
+
+ if ( $rotation ) {
+ if ( !$im->rotateImage( new ImagickPixel( 'white' ), 360 - $rotation ) ) {
+ return $this->getMediaTransformError( $params, "Error rotating $rotation degrees" );
+ }
+ }
+
+ if ( $this->isAnimatedImage( $image ) ) {
+ wfDebug( __METHOD__ . ": Writing animated thumbnail\n" );
+ // This is broken somehow... can't find out how to fix it
+ $result = $im->writeImages( $params['dstPath'], true );
+ } else {
+ $result = $im->writeImage( $params['dstPath'] );
+ }
+ if ( !$result ) {
+ return $this->getMediaTransformError( $params,
+ "Unable to write thumbnail to {$params['dstPath']}" );
+ }
+ } catch ( ImagickException $e ) {
+ return $this->getMediaTransformError( $params, $e->getMessage() );
+ }
+
+ return false;
+ }
+
+ /**
+ * Transform an image using a custom command
+ *
+ * @param File $image File associated with this thumbnail
+ * @param array $params Array with scaler params
+ *
+ * @return MediaTransformError Error|bool object if error occurred, false (=no error) otherwise
+ */
+ protected function transformCustom( $image, $params ) {
+ # Use a custom convert command
+ global $wgCustomConvertCommand;
+
+ # Variables: %s %d %w %h
+ $src = wfEscapeShellArg( $params['srcPath'] );
+ $dst = wfEscapeShellArg( $params['dstPath'] );
+ $cmd = $wgCustomConvertCommand;
+ $cmd = str_replace( '%s', $src, str_replace( '%d', $dst, $cmd ) ); # Filenames
+ $cmd = str_replace( '%h', wfEscapeShellArg( $params['physicalHeight'] ),
+ str_replace( '%w', wfEscapeShellArg( $params['physicalWidth'] ), $cmd ) ); # Size
+ wfDebug( __METHOD__ . ": Running custom convert command $cmd\n" );
+ $retval = 0;
+ $err = wfShellExecWithStderr( $cmd, $retval );
+
+ if ( $retval !== 0 ) {
+ $this->logErrorForExternalProcess( $retval, $err, $cmd );
+
+ return $this->getMediaTransformError( $params, $err );
+ }
+
+ return false; # No error
+ }
+
+ /**
+ * Transform an image using the built in GD library
+ *
+ * @param File $image File associated with this thumbnail
+ * @param array $params Array with scaler params
+ *
+ * @return MediaTransformError|bool Error object if error occurred, false (=no error) otherwise
+ */
+ protected function transformGd( $image, $params ) {
+ # Use PHP's builtin GD library functions.
+ # First find out what kind of file this is, and select the correct
+ # input routine for this.
+
+ $typemap = [
+ 'image/gif' => [ 'imagecreatefromgif', 'palette', false, 'imagegif' ],
+ 'image/jpeg' => [ 'imagecreatefromjpeg', 'truecolor', true,
+ [ __CLASS__, 'imageJpegWrapper' ] ],
+ 'image/png' => [ 'imagecreatefrompng', 'bits', false, 'imagepng' ],
+ 'image/vnd.wap.wbmp' => [ 'imagecreatefromwbmp', 'palette', false, 'imagewbmp' ],
+ 'image/xbm' => [ 'imagecreatefromxbm', 'palette', false, 'imagexbm' ],
+ ];
+
+ if ( !isset( $typemap[$params['mimeType']] ) ) {
+ $err = 'Image type not supported';
+ wfDebug( "$err\n" );
+ $errMsg = wfMessage( 'thumbnail_image-type' )->text();
+
+ return $this->getMediaTransformError( $params, $errMsg );
+ }
+ list( $loader, $colorStyle, $useQuality, $saveType ) = $typemap[$params['mimeType']];
+
+ if ( !function_exists( $loader ) ) {
+ $err = "Incomplete GD library configuration: missing function $loader";
+ wfDebug( "$err\n" );
+ $errMsg = wfMessage( 'thumbnail_gd-library', $loader )->text();
+
+ return $this->getMediaTransformError( $params, $errMsg );
+ }
+
+ if ( !file_exists( $params['srcPath'] ) ) {
+ $err = "File seems to be missing: {$params['srcPath']}";
+ wfDebug( "$err\n" );
+ $errMsg = wfMessage( 'thumbnail_image-missing', $params['srcPath'] )->text();
+
+ return $this->getMediaTransformError( $params, $errMsg );
+ }
+
+ if ( filesize( $params['srcPath'] ) === 0 ) {
+ $err = "Image file size seems to be zero.";
+ wfDebug( "$err\n" );
+ $errMsg = wfMessage( 'thumbnail_image-size-zero', $params['srcPath'] )->text();
+
+ return $this->getMediaTransformError( $params, $errMsg );
+ }
+
+ $src_image = call_user_func( $loader, $params['srcPath'] );
+
+ $rotation = function_exists( 'imagerotate' ) && !isset( $params['disableRotation'] ) ?
+ $this->getRotation( $image ) :
+ 0;
+ list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
+ $dst_image = imagecreatetruecolor( $width, $height );
+
+ // Initialise the destination image to transparent instead of
+ // the default solid black, to support PNG and GIF transparency nicely
+ $background = imagecolorallocate( $dst_image, 0, 0, 0 );
+ imagecolortransparent( $dst_image, $background );
+ imagealphablending( $dst_image, false );
+
+ if ( $colorStyle == 'palette' ) {
+ // Don't resample for paletted GIF images.
+ // It may just uglify them, and completely breaks transparency.
+ imagecopyresized( $dst_image, $src_image,
+ 0, 0, 0, 0,
+ $width, $height,
+ imagesx( $src_image ), imagesy( $src_image ) );
+ } else {
+ imagecopyresampled( $dst_image, $src_image,
+ 0, 0, 0, 0,
+ $width, $height,
+ imagesx( $src_image ), imagesy( $src_image ) );
+ }
+
+ if ( $rotation % 360 != 0 && $rotation % 90 == 0 ) {
+ $rot_image = imagerotate( $dst_image, $rotation, 0 );
+ imagedestroy( $dst_image );
+ $dst_image = $rot_image;
+ }
+
+ imagesavealpha( $dst_image, true );
+
+ $funcParams = [ $dst_image, $params['dstPath'] ];
+ if ( $useQuality && isset( $params['quality'] ) ) {
+ $funcParams[] = $params['quality'];
+ }
+ call_user_func_array( $saveType, $funcParams );
+
+ imagedestroy( $dst_image );
+ imagedestroy( $src_image );
+
+ return false; # No error
+ }
+
+ /**
+ * Callback for transformGd when transforming jpeg images.
+ *
+ * @param resource $dst_image Image resource of the original image
+ * @param string $thumbPath File path to write the thumbnail image to
+ * @param int|null $quality Quality of the thumbnail from 1-100,
+ * or null to use default quality.
+ */
+ static function imageJpegWrapper( $dst_image, $thumbPath, $quality = null ) {
+ global $wgJpegQuality;
+
+ if ( $quality === null ) {
+ $quality = $wgJpegQuality;
+ }
+
+ imageinterlace( $dst_image );
+ imagejpeg( $dst_image, $thumbPath, $quality );
+ }
+
+ /**
+ * Returns whether the current scaler supports rotation (im and gd do)
+ *
+ * @return bool
+ */
+ public function canRotate() {
+ $scaler = $this->getScalerType( null, false );
+ switch ( $scaler ) {
+ case 'im':
+ # ImageMagick supports autorotation
+ return true;
+ case 'imext':
+ # Imagick::rotateImage
+ return true;
+ case 'gd':
+ # GD's imagerotate function is used to rotate images, but not
+ # all precompiled PHP versions have that function
+ return function_exists( 'imagerotate' );
+ default:
+ # Other scalers don't support rotation
+ return false;
+ }
+ }
+
+ /**
+ * @see $wgEnableAutoRotation
+ * @return bool Whether auto rotation is enabled
+ */
+ public function autoRotateEnabled() {
+ global $wgEnableAutoRotation;
+
+ if ( $wgEnableAutoRotation === null ) {
+ // Only enable auto-rotation when we actually can
+ return $this->canRotate();
+ }
+
+ return $wgEnableAutoRotation;
+ }
+
+ /**
+ * @param File $file
+ * @param array $params Rotate parameters.
+ * 'rotation' clockwise rotation in degrees, allowed are multiples of 90
+ * @since 1.21
+ * @return bool|MediaTransformError
+ */
+ public function rotate( $file, $params ) {
+ global $wgImageMagickConvertCommand;
+
+ $rotation = ( $params['rotation'] + $this->getRotation( $file ) ) % 360;
+ $scene = false;
+
+ $scaler = $this->getScalerType( null, false );
+ switch ( $scaler ) {
+ case 'im':
+ $cmd = wfEscapeShellArg( $wgImageMagickConvertCommand ) . " " .
+ wfEscapeShellArg( $this->escapeMagickInput( $params['srcPath'], $scene ) ) .
+ " -rotate " . wfEscapeShellArg( "-$rotation" ) . " " .
+ wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) );
+ wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
+ $retval = 0;
+ $err = wfShellExecWithStderr( $cmd, $retval );
+ if ( $retval !== 0 ) {
+ $this->logErrorForExternalProcess( $retval, $err, $cmd );
+
+ return new MediaTransformError( 'thumbnail_error', 0, 0, $err );
+ }
+
+ return false;
+ case 'imext':
+ $im = new Imagick();
+ $im->readImage( $params['srcPath'] );
+ if ( !$im->rotateImage( new ImagickPixel( 'white' ), 360 - $rotation ) ) {
+ return new MediaTransformError( 'thumbnail_error', 0, 0,
+ "Error rotating $rotation degrees" );
+ }
+ $result = $im->writeImage( $params['dstPath'] );
+ if ( !$result ) {
+ return new MediaTransformError( 'thumbnail_error', 0, 0,
+ "Unable to write image to {$params['dstPath']}" );
+ }
+
+ return false;
+ default:
+ return new MediaTransformError( 'thumbnail_error', 0, 0,
+ "$scaler rotation not implemented" );
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Handler for bitmap images that will be resized by clients.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * Handler for bitmap images that will be resized by clients.
+ *
+ * This is not used by default but can be assigned to some image types
+ * using $wgMediaHandlers.
+ *
+ * @ingroup Media
+ */
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
+class BitmapHandler_ClientOnly extends BitmapHandler {
+
+ /**
+ * @param File $image
+ * @param array &$params
+ * @return bool
+ */
+ function normaliseParams( $image, &$params ) {
+ return ImageHandler::normaliseParams( $image, $params );
+ }
+
+ /**
+ * @param File $image
+ * @param string $dstPath
+ * @param string $dstUrl
+ * @param array $params
+ * @param int $flags
+ * @return ThumbnailImage|TransformParameterError
+ */
+ function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
+ if ( !$this->normaliseParams( $image, $params ) ) {
+ return new TransformParameterError( $params );
+ }
+
+ return new ThumbnailImage( $image, $image->getUrl(), $image->getLocalRefPath(), $params );
+ }
+}
+++ /dev/null
-<?php
-/**
- * Handler for bitmap images that will be resized by clients.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-/**
- * Handler for bitmap images that will be resized by clients.
- *
- * This is not used by default but can be assigned to some image types
- * using $wgMediaHandlers.
- *
- * @ingroup Media
- */
-// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
-class BitmapHandler_ClientOnly extends BitmapHandler {
-
- /**
- * @param File $image
- * @param array &$params
- * @return bool
- */
- function normaliseParams( $image, &$params ) {
- return ImageHandler::normaliseParams( $image, $params );
- }
-
- /**
- * @param File $image
- * @param string $dstPath
- * @param string $dstUrl
- * @param array $params
- * @param int $flags
- * @return ThumbnailImage|TransformParameterError
- */
- function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
- if ( !$this->normaliseParams( $image, $params ) ) {
- return new TransformParameterError( $params );
- }
-
- return new ThumbnailImage( $image, $image->getUrl(), $image->getLocalRefPath(), $params );
- }
-}
--- /dev/null
+<?php
+/**
+ * Handler for Microsoft's bitmap format.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * Handler for Microsoft's bitmap format; getimagesize() doesn't
+ * support these files
+ *
+ * @ingroup Media
+ */
+class BmpHandler extends BitmapHandler {
+ /**
+ * @param File $file
+ * @return bool
+ */
+ public function mustRender( $file ) {
+ return true;
+ }
+
+ /**
+ * Render files as PNG
+ *
+ * @param string $text
+ * @param string $mime
+ * @param array $params
+ * @return array
+ */
+ function getThumbType( $text, $mime, $params = null ) {
+ return [ 'png', 'image/png' ];
+ }
+
+ /**
+ * Get width and height from the bmp header.
+ *
+ * @param File|FSFile $image
+ * @param string $filename
+ * @return array
+ */
+ function getImageSize( $image, $filename ) {
+ $f = fopen( $filename, 'rb' );
+ if ( !$f ) {
+ return false;
+ }
+ $header = fread( $f, 54 );
+ fclose( $f );
+
+ // Extract binary form of width and height from the header
+ $w = substr( $header, 18, 4 );
+ $h = substr( $header, 22, 4 );
+
+ // Convert the unsigned long 32 bits (little endian):
+ try {
+ $w = wfUnpack( 'V', $w, 4 );
+ $h = wfUnpack( 'V', $h, 4 );
+ } catch ( Exception $e ) {
+ return false;
+ }
+
+ return [ $w[1], $h[1] ];
+ }
+}
+++ /dev/null
-<?php
-/**
- * Handler for DjVu images.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-/**
- * Handler for DjVu images
- *
- * @ingroup Media
- */
-class DjVuHandler extends ImageHandler {
- const EXPENSIVE_SIZE_LIMIT = 10485760; // 10MiB
-
- /**
- * @return bool
- */
- function isEnabled() {
- global $wgDjvuRenderer, $wgDjvuDump, $wgDjvuToXML;
- if ( !$wgDjvuRenderer || ( !$wgDjvuDump && !$wgDjvuToXML ) ) {
- wfDebug( "DjVu is disabled, please set \$wgDjvuRenderer and \$wgDjvuDump\n" );
-
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * @param File $file
- * @return bool
- */
- public function mustRender( $file ) {
- return true;
- }
-
- /**
- * True if creating thumbnails from the file is large or otherwise resource-intensive.
- * @param File $file
- * @return bool
- */
- public function isExpensiveToThumbnail( $file ) {
- return $file->getSize() > static::EXPENSIVE_SIZE_LIMIT;
- }
-
- /**
- * @param File $file
- * @return bool
- */
- public function isMultiPage( $file ) {
- return true;
- }
-
- /**
- * @return array
- */
- public function getParamMap() {
- return [
- 'img_width' => 'width',
- 'img_page' => 'page',
- ];
- }
-
- /**
- * @param string $name
- * @param mixed $value
- * @return bool
- */
- public function validateParam( $name, $value ) {
- if ( $name === 'page' && trim( $value ) !== (string)intval( $value ) ) {
- // Extra junk on the end of page, probably actually a caption
- // e.g. [[File:Foo.djvu|thumb|Page 3 of the document shows foo]]
- return false;
- }
- if ( in_array( $name, [ 'width', 'height', 'page' ] ) ) {
- if ( $value <= 0 ) {
- return false;
- } else {
- return true;
- }
- } else {
- return false;
- }
- }
-
- /**
- * @param array $params
- * @return bool|string
- */
- public function makeParamString( $params ) {
- $page = isset( $params['page'] ) ? $params['page'] : 1;
- if ( !isset( $params['width'] ) ) {
- return false;
- }
-
- return "page{$page}-{$params['width']}px";
- }
-
- /**
- * @param string $str
- * @return array|bool
- */
- public function parseParamString( $str ) {
- $m = false;
- if ( preg_match( '/^page(\d+)-(\d+)px$/', $str, $m ) ) {
- return [ 'width' => $m[2], 'page' => $m[1] ];
- } else {
- return false;
- }
- }
-
- /**
- * @param array $params
- * @return array
- */
- function getScriptParams( $params ) {
- return [
- 'width' => $params['width'],
- 'page' => $params['page'],
- ];
- }
-
- /**
- * @param File $image
- * @param string $dstPath
- * @param string $dstUrl
- * @param array $params
- * @param int $flags
- * @return MediaTransformError|ThumbnailImage|TransformParameterError
- */
- function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
- global $wgDjvuRenderer, $wgDjvuPostProcessor;
-
- if ( !$this->normaliseParams( $image, $params ) ) {
- return new TransformParameterError( $params );
- }
- $width = $params['width'];
- $height = $params['height'];
- $page = $params['page'];
-
- if ( $flags & self::TRANSFORM_LATER ) {
- $params = [
- 'width' => $width,
- 'height' => $height,
- 'page' => $page
- ];
-
- return new ThumbnailImage( $image, $dstUrl, $dstPath, $params );
- }
-
- if ( !wfMkdirParents( dirname( $dstPath ), null, __METHOD__ ) ) {
- return new MediaTransformError(
- 'thumbnail_error',
- $width,
- $height,
- wfMessage( 'thumbnail_dest_directory' )
- );
- }
-
- // Get local copy source for shell scripts
- // Thumbnail extraction is very inefficient for large files.
- // Provide a way to pool count limit the number of downloaders.
- if ( $image->getSize() >= 1e7 ) { // 10MB
- $work = new PoolCounterWorkViaCallback( 'GetLocalFileCopy', sha1( $image->getName() ),
- [
- 'doWork' => function () use ( $image ) {
- return $image->getLocalRefPath();
- }
- ]
- );
- $srcPath = $work->execute();
- } else {
- $srcPath = $image->getLocalRefPath();
- }
-
- if ( $srcPath === false ) { // Failed to get local copy
- wfDebugLog( 'thumbnail',
- sprintf( 'Thumbnail failed on %s: could not get local copy of "%s"',
- wfHostname(), $image->getName() ) );
-
- return new MediaTransformError( 'thumbnail_error',
- $params['width'], $params['height'],
- wfMessage( 'filemissing' )
- );
- }
-
- # Use a subshell (brackets) to aggregate stderr from both pipeline commands
- # before redirecting it to the overall stdout. This works in both Linux and Windows XP.
- $cmd = '(' . wfEscapeShellArg(
- $wgDjvuRenderer,
- "-format=ppm",
- "-page={$page}",
- "-size={$params['physicalWidth']}x{$params['physicalHeight']}",
- $srcPath );
- if ( $wgDjvuPostProcessor ) {
- $cmd .= " | {$wgDjvuPostProcessor}";
- }
- $cmd .= ' > ' . wfEscapeShellArg( $dstPath ) . ') 2>&1';
- wfDebug( __METHOD__ . ": $cmd\n" );
- $retval = '';
- $err = wfShellExec( $cmd, $retval );
-
- $removed = $this->removeBadFile( $dstPath, $retval );
- if ( $retval != 0 || $removed ) {
- $this->logErrorForExternalProcess( $retval, $err, $cmd );
- return new MediaTransformError( 'thumbnail_error', $width, $height, $err );
- } else {
- $params = [
- 'width' => $width,
- 'height' => $height,
- 'page' => $page
- ];
-
- return new ThumbnailImage( $image, $dstUrl, $dstPath, $params );
- }
- }
-
- /**
- * Cache an instance of DjVuImage in an Image object, return that instance
- *
- * @param File|FSFile $image
- * @param string $path
- * @return DjVuImage
- */
- function getDjVuImage( $image, $path ) {
- if ( !$image ) {
- $deja = new DjVuImage( $path );
- } elseif ( !isset( $image->dejaImage ) ) {
- $deja = $image->dejaImage = new DjVuImage( $path );
- } else {
- $deja = $image->dejaImage;
- }
-
- return $deja;
- }
-
- /**
- * Get metadata, unserializing it if neccessary.
- *
- * @param File $file The DjVu file in question
- * @return string XML metadata as a string.
- * @throws MWException
- */
- private function getUnserializedMetadata( File $file ) {
- $metadata = $file->getMetadata();
- if ( substr( $metadata, 0, 3 ) === '<?xml' ) {
- // Old style. Not serialized but instead just a raw string of XML.
- return $metadata;
- }
-
- Wikimedia\suppressWarnings();
- $unser = unserialize( $metadata );
- Wikimedia\restoreWarnings();
- if ( is_array( $unser ) ) {
- if ( isset( $unser['error'] ) ) {
- return false;
- } elseif ( isset( $unser['xml'] ) ) {
- return $unser['xml'];
- } else {
- // Should never ever reach here.
- throw new MWException( "Error unserializing DjVu metadata." );
- }
- }
-
- // unserialize failed. Guess it wasn't really serialized after all,
- return $metadata;
- }
-
- /**
- * Cache a document tree for the DjVu XML metadata
- * @param File $image
- * @param bool $gettext DOCUMENT (Default: false)
- * @return bool|SimpleXMLElement
- */
- public function getMetaTree( $image, $gettext = false ) {
- if ( $gettext && isset( $image->djvuTextTree ) ) {
- return $image->djvuTextTree;
- }
- if ( !$gettext && isset( $image->dejaMetaTree ) ) {
- return $image->dejaMetaTree;
- }
-
- $metadata = $this->getUnserializedMetadata( $image );
- if ( !$this->isMetadataValid( $image, $metadata ) ) {
- wfDebug( "DjVu XML metadata is invalid or missing, should have been fixed in upgradeRow\n" );
-
- return false;
- }
-
- $trees = $this->extractTreesFromMetadata( $metadata );
- $image->djvuTextTree = $trees['TextTree'];
- $image->dejaMetaTree = $trees['MetaTree'];
-
- if ( $gettext ) {
- return $image->djvuTextTree;
- } else {
- return $image->dejaMetaTree;
- }
- }
-
- /**
- * Extracts metadata and text trees from metadata XML in string form
- * @param string $metadata XML metadata as a string
- * @return array
- */
- protected function extractTreesFromMetadata( $metadata ) {
- Wikimedia\suppressWarnings();
- try {
- // Set to false rather than null to avoid further attempts
- $metaTree = false;
- $textTree = false;
- $tree = new SimpleXMLElement( $metadata, LIBXML_PARSEHUGE );
- if ( $tree->getName() == 'mw-djvu' ) {
- /** @var SimpleXMLElement $b */
- foreach ( $tree->children() as $b ) {
- if ( $b->getName() == 'DjVuTxt' ) {
- // @todo File::djvuTextTree and File::dejaMetaTree are declared
- // dynamically. Add a public File::$data to facilitate this?
- $textTree = $b;
- } elseif ( $b->getName() == 'DjVuXML' ) {
- $metaTree = $b;
- }
- }
- } else {
- $metaTree = $tree;
- }
- } catch ( Exception $e ) {
- wfDebug( "Bogus multipage XML metadata\n" );
- }
- Wikimedia\restoreWarnings();
-
- return [ 'MetaTree' => $metaTree, 'TextTree' => $textTree ];
- }
-
- function getImageSize( $image, $path ) {
- return $this->getDjVuImage( $image, $path )->getImageSize();
- }
-
- function getThumbType( $ext, $mime, $params = null ) {
- global $wgDjvuOutputExtension;
- static $mime;
- if ( !isset( $mime ) ) {
- $magic = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer();
- $mime = $magic->guessTypesForExtension( $wgDjvuOutputExtension );
- }
-
- return [ $wgDjvuOutputExtension, $mime ];
- }
-
- function getMetadata( $image, $path ) {
- wfDebug( "Getting DjVu metadata for $path\n" );
-
- $xml = $this->getDjVuImage( $image, $path )->retrieveMetaData();
- if ( $xml === false ) {
- // Special value so that we don't repetitively try and decode a broken file.
- return serialize( [ 'error' => 'Error extracting metadata' ] );
- } else {
- return serialize( [ 'xml' => $xml ] );
- }
- }
-
- function getMetadataType( $image ) {
- return 'djvuxml';
- }
-
- function isMetadataValid( $image, $metadata ) {
- return !empty( $metadata ) && $metadata != serialize( [] );
- }
-
- function pageCount( File $image ) {
- $info = $this->getDimensionInfo( $image );
-
- return $info ? $info['pageCount'] : false;
- }
-
- function getPageDimensions( File $image, $page ) {
- $index = $page - 1; // MW starts pages at 1
-
- $info = $this->getDimensionInfo( $image );
- if ( $info && isset( $info['dimensionsByPage'][$index] ) ) {
- return $info['dimensionsByPage'][$index];
- }
-
- return false;
- }
-
- protected function getDimensionInfo( File $file ) {
- $cache = ObjectCache::getMainWANInstance();
- return $cache->getWithSetCallback(
- $cache->makeKey( 'file-djvu', 'dimensions', $file->getSha1() ),
- $cache::TTL_INDEFINITE,
- function () use ( $file ) {
- $tree = $this->getMetaTree( $file );
- return $this->getDimensionInfoFromMetaTree( $tree );
- },
- [ 'pcTTL' => $cache::TTL_INDEFINITE ]
- );
- }
-
- /**
- * Given an XML metadata tree, returns dimension information about the document
- * @param bool|SimpleXMLElement $metatree The file's XML metadata tree
- * @return bool|array
- */
- protected function getDimensionInfoFromMetaTree( $metatree ) {
- if ( !$metatree ) {
- return false;
- }
-
- $dimsByPage = [];
- $count = count( $metatree->xpath( '//OBJECT' ) );
- for ( $i = 0; $i < $count; $i++ ) {
- $o = $metatree->BODY[0]->OBJECT[$i];
- if ( $o ) {
- $dimsByPage[$i] = [
- 'width' => (int)$o['width'],
- 'height' => (int)$o['height'],
- ];
- } else {
- $dimsByPage[$i] = false;
- }
- }
-
- return [ 'pageCount' => $count, 'dimensionsByPage' => $dimsByPage ];
- }
-
- /**
- * @param File $image
- * @param int $page Page number to get information for
- * @return bool|string Page text or false when no text found.
- */
- function getPageText( File $image, $page ) {
- $tree = $this->getMetaTree( $image, true );
- if ( !$tree ) {
- return false;
- }
-
- $o = $tree->BODY[0]->PAGE[$page - 1];
- if ( $o ) {
- $txt = $o['value'];
-
- return $txt;
- } else {
- return false;
- }
- }
-}
--- /dev/null
+<?php
+/**
+ * Handler for DjVu images.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * Handler for DjVu images
+ *
+ * @ingroup Media
+ */
+class DjVuHandler extends ImageHandler {
+ const EXPENSIVE_SIZE_LIMIT = 10485760; // 10MiB
+
+ /**
+ * @return bool
+ */
+ function isEnabled() {
+ global $wgDjvuRenderer, $wgDjvuDump, $wgDjvuToXML;
+ if ( !$wgDjvuRenderer || ( !$wgDjvuDump && !$wgDjvuToXML ) ) {
+ wfDebug( "DjVu is disabled, please set \$wgDjvuRenderer and \$wgDjvuDump\n" );
+
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * @param File $file
+ * @return bool
+ */
+ public function mustRender( $file ) {
+ return true;
+ }
+
+ /**
+ * True if creating thumbnails from the file is large or otherwise resource-intensive.
+ * @param File $file
+ * @return bool
+ */
+ public function isExpensiveToThumbnail( $file ) {
+ return $file->getSize() > static::EXPENSIVE_SIZE_LIMIT;
+ }
+
+ /**
+ * @param File $file
+ * @return bool
+ */
+ public function isMultiPage( $file ) {
+ return true;
+ }
+
+ /**
+ * @return array
+ */
+ public function getParamMap() {
+ return [
+ 'img_width' => 'width',
+ 'img_page' => 'page',
+ ];
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $value
+ * @return bool
+ */
+ public function validateParam( $name, $value ) {
+ if ( $name === 'page' && trim( $value ) !== (string)intval( $value ) ) {
+ // Extra junk on the end of page, probably actually a caption
+ // e.g. [[File:Foo.djvu|thumb|Page 3 of the document shows foo]]
+ return false;
+ }
+ if ( in_array( $name, [ 'width', 'height', 'page' ] ) ) {
+ if ( $value <= 0 ) {
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param array $params
+ * @return bool|string
+ */
+ public function makeParamString( $params ) {
+ $page = isset( $params['page'] ) ? $params['page'] : 1;
+ if ( !isset( $params['width'] ) ) {
+ return false;
+ }
+
+ return "page{$page}-{$params['width']}px";
+ }
+
+ /**
+ * @param string $str
+ * @return array|bool
+ */
+ public function parseParamString( $str ) {
+ $m = false;
+ if ( preg_match( '/^page(\d+)-(\d+)px$/', $str, $m ) ) {
+ return [ 'width' => $m[2], 'page' => $m[1] ];
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param array $params
+ * @return array
+ */
+ function getScriptParams( $params ) {
+ return [
+ 'width' => $params['width'],
+ 'page' => $params['page'],
+ ];
+ }
+
+ /**
+ * @param File $image
+ * @param string $dstPath
+ * @param string $dstUrl
+ * @param array $params
+ * @param int $flags
+ * @return MediaTransformError|ThumbnailImage|TransformParameterError
+ */
+ function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
+ global $wgDjvuRenderer, $wgDjvuPostProcessor;
+
+ if ( !$this->normaliseParams( $image, $params ) ) {
+ return new TransformParameterError( $params );
+ }
+ $width = $params['width'];
+ $height = $params['height'];
+ $page = $params['page'];
+
+ if ( $flags & self::TRANSFORM_LATER ) {
+ $params = [
+ 'width' => $width,
+ 'height' => $height,
+ 'page' => $page
+ ];
+
+ return new ThumbnailImage( $image, $dstUrl, $dstPath, $params );
+ }
+
+ if ( !wfMkdirParents( dirname( $dstPath ), null, __METHOD__ ) ) {
+ return new MediaTransformError(
+ 'thumbnail_error',
+ $width,
+ $height,
+ wfMessage( 'thumbnail_dest_directory' )
+ );
+ }
+
+ // Get local copy source for shell scripts
+ // Thumbnail extraction is very inefficient for large files.
+ // Provide a way to pool count limit the number of downloaders.
+ if ( $image->getSize() >= 1e7 ) { // 10MB
+ $work = new PoolCounterWorkViaCallback( 'GetLocalFileCopy', sha1( $image->getName() ),
+ [
+ 'doWork' => function () use ( $image ) {
+ return $image->getLocalRefPath();
+ }
+ ]
+ );
+ $srcPath = $work->execute();
+ } else {
+ $srcPath = $image->getLocalRefPath();
+ }
+
+ if ( $srcPath === false ) { // Failed to get local copy
+ wfDebugLog( 'thumbnail',
+ sprintf( 'Thumbnail failed on %s: could not get local copy of "%s"',
+ wfHostname(), $image->getName() ) );
+
+ return new MediaTransformError( 'thumbnail_error',
+ $params['width'], $params['height'],
+ wfMessage( 'filemissing' )
+ );
+ }
+
+ # Use a subshell (brackets) to aggregate stderr from both pipeline commands
+ # before redirecting it to the overall stdout. This works in both Linux and Windows XP.
+ $cmd = '(' . wfEscapeShellArg(
+ $wgDjvuRenderer,
+ "-format=ppm",
+ "-page={$page}",
+ "-size={$params['physicalWidth']}x{$params['physicalHeight']}",
+ $srcPath );
+ if ( $wgDjvuPostProcessor ) {
+ $cmd .= " | {$wgDjvuPostProcessor}";
+ }
+ $cmd .= ' > ' . wfEscapeShellArg( $dstPath ) . ') 2>&1';
+ wfDebug( __METHOD__ . ": $cmd\n" );
+ $retval = '';
+ $err = wfShellExec( $cmd, $retval );
+
+ $removed = $this->removeBadFile( $dstPath, $retval );
+ if ( $retval != 0 || $removed ) {
+ $this->logErrorForExternalProcess( $retval, $err, $cmd );
+ return new MediaTransformError( 'thumbnail_error', $width, $height, $err );
+ } else {
+ $params = [
+ 'width' => $width,
+ 'height' => $height,
+ 'page' => $page
+ ];
+
+ return new ThumbnailImage( $image, $dstUrl, $dstPath, $params );
+ }
+ }
+
+ /**
+ * Cache an instance of DjVuImage in an Image object, return that instance
+ *
+ * @param File|FSFile $image
+ * @param string $path
+ * @return DjVuImage
+ */
+ function getDjVuImage( $image, $path ) {
+ if ( !$image ) {
+ $deja = new DjVuImage( $path );
+ } elseif ( !isset( $image->dejaImage ) ) {
+ $deja = $image->dejaImage = new DjVuImage( $path );
+ } else {
+ $deja = $image->dejaImage;
+ }
+
+ return $deja;
+ }
+
+ /**
+ * Get metadata, unserializing it if neccessary.
+ *
+ * @param File $file The DjVu file in question
+ * @return string XML metadata as a string.
+ * @throws MWException
+ */
+ private function getUnserializedMetadata( File $file ) {
+ $metadata = $file->getMetadata();
+ if ( substr( $metadata, 0, 3 ) === '<?xml' ) {
+ // Old style. Not serialized but instead just a raw string of XML.
+ return $metadata;
+ }
+
+ Wikimedia\suppressWarnings();
+ $unser = unserialize( $metadata );
+ Wikimedia\restoreWarnings();
+ if ( is_array( $unser ) ) {
+ if ( isset( $unser['error'] ) ) {
+ return false;
+ } elseif ( isset( $unser['xml'] ) ) {
+ return $unser['xml'];
+ } else {
+ // Should never ever reach here.
+ throw new MWException( "Error unserializing DjVu metadata." );
+ }
+ }
+
+ // unserialize failed. Guess it wasn't really serialized after all,
+ return $metadata;
+ }
+
+ /**
+ * Cache a document tree for the DjVu XML metadata
+ * @param File $image
+ * @param bool $gettext DOCUMENT (Default: false)
+ * @return bool|SimpleXMLElement
+ */
+ public function getMetaTree( $image, $gettext = false ) {
+ if ( $gettext && isset( $image->djvuTextTree ) ) {
+ return $image->djvuTextTree;
+ }
+ if ( !$gettext && isset( $image->dejaMetaTree ) ) {
+ return $image->dejaMetaTree;
+ }
+
+ $metadata = $this->getUnserializedMetadata( $image );
+ if ( !$this->isMetadataValid( $image, $metadata ) ) {
+ wfDebug( "DjVu XML metadata is invalid or missing, should have been fixed in upgradeRow\n" );
+
+ return false;
+ }
+
+ $trees = $this->extractTreesFromMetadata( $metadata );
+ $image->djvuTextTree = $trees['TextTree'];
+ $image->dejaMetaTree = $trees['MetaTree'];
+
+ if ( $gettext ) {
+ return $image->djvuTextTree;
+ } else {
+ return $image->dejaMetaTree;
+ }
+ }
+
+ /**
+ * Extracts metadata and text trees from metadata XML in string form
+ * @param string $metadata XML metadata as a string
+ * @return array
+ */
+ protected function extractTreesFromMetadata( $metadata ) {
+ Wikimedia\suppressWarnings();
+ try {
+ // Set to false rather than null to avoid further attempts
+ $metaTree = false;
+ $textTree = false;
+ $tree = new SimpleXMLElement( $metadata, LIBXML_PARSEHUGE );
+ if ( $tree->getName() == 'mw-djvu' ) {
+ /** @var SimpleXMLElement $b */
+ foreach ( $tree->children() as $b ) {
+ if ( $b->getName() == 'DjVuTxt' ) {
+ // @todo File::djvuTextTree and File::dejaMetaTree are declared
+ // dynamically. Add a public File::$data to facilitate this?
+ $textTree = $b;
+ } elseif ( $b->getName() == 'DjVuXML' ) {
+ $metaTree = $b;
+ }
+ }
+ } else {
+ $metaTree = $tree;
+ }
+ } catch ( Exception $e ) {
+ wfDebug( "Bogus multipage XML metadata\n" );
+ }
+ Wikimedia\restoreWarnings();
+
+ return [ 'MetaTree' => $metaTree, 'TextTree' => $textTree ];
+ }
+
+ function getImageSize( $image, $path ) {
+ return $this->getDjVuImage( $image, $path )->getImageSize();
+ }
+
+ function getThumbType( $ext, $mime, $params = null ) {
+ global $wgDjvuOutputExtension;
+ static $mime;
+ if ( !isset( $mime ) ) {
+ $magic = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer();
+ $mime = $magic->guessTypesForExtension( $wgDjvuOutputExtension );
+ }
+
+ return [ $wgDjvuOutputExtension, $mime ];
+ }
+
+ function getMetadata( $image, $path ) {
+ wfDebug( "Getting DjVu metadata for $path\n" );
+
+ $xml = $this->getDjVuImage( $image, $path )->retrieveMetaData();
+ if ( $xml === false ) {
+ // Special value so that we don't repetitively try and decode a broken file.
+ return serialize( [ 'error' => 'Error extracting metadata' ] );
+ } else {
+ return serialize( [ 'xml' => $xml ] );
+ }
+ }
+
+ function getMetadataType( $image ) {
+ return 'djvuxml';
+ }
+
+ function isMetadataValid( $image, $metadata ) {
+ return !empty( $metadata ) && $metadata != serialize( [] );
+ }
+
+ function pageCount( File $image ) {
+ $info = $this->getDimensionInfo( $image );
+
+ return $info ? $info['pageCount'] : false;
+ }
+
+ function getPageDimensions( File $image, $page ) {
+ $index = $page - 1; // MW starts pages at 1
+
+ $info = $this->getDimensionInfo( $image );
+ if ( $info && isset( $info['dimensionsByPage'][$index] ) ) {
+ return $info['dimensionsByPage'][$index];
+ }
+
+ return false;
+ }
+
+ protected function getDimensionInfo( File $file ) {
+ $cache = ObjectCache::getMainWANInstance();
+ return $cache->getWithSetCallback(
+ $cache->makeKey( 'file-djvu', 'dimensions', $file->getSha1() ),
+ $cache::TTL_INDEFINITE,
+ function () use ( $file ) {
+ $tree = $this->getMetaTree( $file );
+ return $this->getDimensionInfoFromMetaTree( $tree );
+ },
+ [ 'pcTTL' => $cache::TTL_INDEFINITE ]
+ );
+ }
+
+ /**
+ * Given an XML metadata tree, returns dimension information about the document
+ * @param bool|SimpleXMLElement $metatree The file's XML metadata tree
+ * @return bool|array
+ */
+ protected function getDimensionInfoFromMetaTree( $metatree ) {
+ if ( !$metatree ) {
+ return false;
+ }
+
+ $dimsByPage = [];
+ $count = count( $metatree->xpath( '//OBJECT' ) );
+ for ( $i = 0; $i < $count; $i++ ) {
+ $o = $metatree->BODY[0]->OBJECT[$i];
+ if ( $o ) {
+ $dimsByPage[$i] = [
+ 'width' => (int)$o['width'],
+ 'height' => (int)$o['height'],
+ ];
+ } else {
+ $dimsByPage[$i] = false;
+ }
+ }
+
+ return [ 'pageCount' => $count, 'dimensionsByPage' => $dimsByPage ];
+ }
+
+ /**
+ * @param File $image
+ * @param int $page Page number to get information for
+ * @return bool|string Page text or false when no text found.
+ */
+ function getPageText( File $image, $page ) {
+ $tree = $this->getMetaTree( $image, true );
+ if ( !$tree ) {
+ return false;
+ }
+
+ $o = $tree->BODY[0]->PAGE[$page - 1];
+ if ( $o ) {
+ $txt = $o['value'];
+
+ return $txt;
+ } else {
+ return false;
+ }
+ }
+}
+++ /dev/null
-<?php
-/**
- * Handler for bitmap images with exif metadata.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-/**
- * Stuff specific to JPEG and (built-in) TIFF handler.
- * All metadata related, since both JPEG and TIFF support Exif.
- *
- * @ingroup Media
- */
-class ExifBitmapHandler extends BitmapHandler {
- const BROKEN_FILE = '-1'; // error extracting metadata
- const OLD_BROKEN_FILE = '0'; // outdated error extracting metadata.
-
- function convertMetadataVersion( $metadata, $version = 1 ) {
- // basically flattens arrays.
- $version = intval( explode( ';', $version, 2 )[0] );
- if ( $version < 1 || $version >= 2 ) {
- return $metadata;
- }
-
- $avoidHtml = true;
-
- if ( !is_array( $metadata ) ) {
- $metadata = unserialize( $metadata );
- }
- if ( !isset( $metadata['MEDIAWIKI_EXIF_VERSION'] ) || $metadata['MEDIAWIKI_EXIF_VERSION'] != 2 ) {
- return $metadata;
- }
-
- // Treat Software as a special case because in can contain
- // an array of (SoftwareName, Version).
- if ( isset( $metadata['Software'] )
- && is_array( $metadata['Software'] )
- && is_array( $metadata['Software'][0] )
- && isset( $metadata['Software'][0][0] )
- && isset( $metadata['Software'][0][1] )
- ) {
- $metadata['Software'] = $metadata['Software'][0][0] . ' (Version '
- . $metadata['Software'][0][1] . ')';
- }
-
- $formatter = new FormatMetadata;
-
- // ContactInfo also has to be dealt with specially
- if ( isset( $metadata['Contact'] ) ) {
- $metadata['Contact'] =
- $formatter->collapseContactInfo(
- $metadata['Contact'] );
- }
-
- foreach ( $metadata as &$val ) {
- if ( is_array( $val ) ) {
- $val = $formatter->flattenArrayReal( $val, 'ul', $avoidHtml );
- }
- }
- $metadata['MEDIAWIKI_EXIF_VERSION'] = 1;
-
- return $metadata;
- }
-
- /**
- * @param File $image
- * @param array $metadata
- * @return bool|int
- */
- function isMetadataValid( $image, $metadata ) {
- global $wgShowEXIF;
- if ( !$wgShowEXIF ) {
- # Metadata disabled and so an empty field is expected
- return self::METADATA_GOOD;
- }
- if ( $metadata === self::OLD_BROKEN_FILE ) {
- # Old special value indicating that there is no Exif data in the file.
- # or that there was an error well extracting the metadata.
- wfDebug( __METHOD__ . ": back-compat version\n" );
-
- return self::METADATA_COMPATIBLE;
- }
- if ( $metadata === self::BROKEN_FILE ) {
- return self::METADATA_GOOD;
- }
- Wikimedia\suppressWarnings();
- $exif = unserialize( $metadata );
- Wikimedia\restoreWarnings();
- if ( !isset( $exif['MEDIAWIKI_EXIF_VERSION'] )
- || $exif['MEDIAWIKI_EXIF_VERSION'] != Exif::version()
- ) {
- if ( isset( $exif['MEDIAWIKI_EXIF_VERSION'] )
- && $exif['MEDIAWIKI_EXIF_VERSION'] == 1
- ) {
- // back-compatible but old
- wfDebug( __METHOD__ . ": back-compat version\n" );
-
- return self::METADATA_COMPATIBLE;
- }
- # Wrong (non-compatible) version
- wfDebug( __METHOD__ . ": wrong version\n" );
-
- return self::METADATA_BAD;
- }
-
- return self::METADATA_GOOD;
- }
-
- /**
- * @param File $image
- * @param bool|IContextSource $context Context to use (optional)
- * @return array|bool
- */
- function formatMetadata( $image, $context = false ) {
- $meta = $this->getCommonMetaArray( $image );
- if ( count( $meta ) === 0 ) {
- return false;
- }
-
- return $this->formatMetadataHelper( $meta, $context );
- }
-
- public function getCommonMetaArray( File $file ) {
- $metadata = $file->getMetadata();
- if ( $metadata === self::OLD_BROKEN_FILE
- || $metadata === self::BROKEN_FILE
- || $this->isMetadataValid( $file, $metadata ) === self::METADATA_BAD
- ) {
- // So we don't try and display metadata from PagedTiffHandler
- // for example when using InstantCommons.
- return [];
- }
-
- $exif = unserialize( $metadata );
- if ( !$exif ) {
- return [];
- }
- unset( $exif['MEDIAWIKI_EXIF_VERSION'] );
-
- return $exif;
- }
-
- function getMetadataType( $image ) {
- return 'exif';
- }
-
- /**
- * Wrapper for base classes ImageHandler::getImageSize() that checks for
- * rotation reported from metadata and swaps the sizes to match.
- *
- * @param File|FSFile $image
- * @param string $path
- * @return array
- */
- function getImageSize( $image, $path ) {
- $gis = parent::getImageSize( $image, $path );
-
- // Don't just call $image->getMetadata(); FSFile::getPropsFromPath() calls us with a bogus object.
- // This may mean we read EXIF data twice on initial upload.
- if ( $this->autoRotateEnabled() ) {
- $meta = $this->getMetadata( $image, $path );
- $rotation = $this->getRotationForExif( $meta );
- } else {
- $rotation = 0;
- }
-
- if ( $rotation == 90 || $rotation == 270 ) {
- $width = $gis[0];
- $gis[0] = $gis[1];
- $gis[1] = $width;
- }
-
- return $gis;
- }
-
- /**
- * On supporting image formats, try to read out the low-level orientation
- * of the file and return the angle that the file needs to be rotated to
- * be viewed.
- *
- * This information is only useful when manipulating the original file;
- * the width and height we normally work with is logical, and will match
- * any produced output views.
- *
- * @param File $file
- * @return int 0, 90, 180 or 270
- */
- public function getRotation( $file ) {
- if ( !$this->autoRotateEnabled() ) {
- return 0;
- }
-
- $data = $file->getMetadata();
-
- return $this->getRotationForExif( $data );
- }
-
- /**
- * Given a chunk of serialized Exif metadata, return the orientation as
- * degrees of rotation.
- *
- * @param string $data
- * @return int 0, 90, 180 or 270
- * @todo FIXME: Orientation can include flipping as well; see if this is an issue!
- */
- protected function getRotationForExif( $data ) {
- if ( !$data ) {
- return 0;
- }
- Wikimedia\suppressWarnings();
- $data = unserialize( $data );
- Wikimedia\restoreWarnings();
- if ( isset( $data['Orientation'] ) ) {
- # See http://sylvana.net/jpegcrop/exif_orientation.html
- switch ( $data['Orientation'] ) {
- case 8:
- return 90;
- case 3:
- return 180;
- case 6:
- return 270;
- default:
- return 0;
- }
- }
-
- return 0;
- }
-}
--- /dev/null
+<?php
+/**
+ * Handler for bitmap images with exif metadata.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * Stuff specific to JPEG and (built-in) TIFF handler.
+ * All metadata related, since both JPEG and TIFF support Exif.
+ *
+ * @ingroup Media
+ */
+class ExifBitmapHandler extends BitmapHandler {
+ const BROKEN_FILE = '-1'; // error extracting metadata
+ const OLD_BROKEN_FILE = '0'; // outdated error extracting metadata.
+
+ function convertMetadataVersion( $metadata, $version = 1 ) {
+ // basically flattens arrays.
+ $version = intval( explode( ';', $version, 2 )[0] );
+ if ( $version < 1 || $version >= 2 ) {
+ return $metadata;
+ }
+
+ $avoidHtml = true;
+
+ if ( !is_array( $metadata ) ) {
+ $metadata = unserialize( $metadata );
+ }
+ if ( !isset( $metadata['MEDIAWIKI_EXIF_VERSION'] ) || $metadata['MEDIAWIKI_EXIF_VERSION'] != 2 ) {
+ return $metadata;
+ }
+
+ // Treat Software as a special case because in can contain
+ // an array of (SoftwareName, Version).
+ if ( isset( $metadata['Software'] )
+ && is_array( $metadata['Software'] )
+ && is_array( $metadata['Software'][0] )
+ && isset( $metadata['Software'][0][0] )
+ && isset( $metadata['Software'][0][1] )
+ ) {
+ $metadata['Software'] = $metadata['Software'][0][0] . ' (Version '
+ . $metadata['Software'][0][1] . ')';
+ }
+
+ $formatter = new FormatMetadata;
+
+ // ContactInfo also has to be dealt with specially
+ if ( isset( $metadata['Contact'] ) ) {
+ $metadata['Contact'] =
+ $formatter->collapseContactInfo(
+ $metadata['Contact'] );
+ }
+
+ foreach ( $metadata as &$val ) {
+ if ( is_array( $val ) ) {
+ $val = $formatter->flattenArrayReal( $val, 'ul', $avoidHtml );
+ }
+ }
+ $metadata['MEDIAWIKI_EXIF_VERSION'] = 1;
+
+ return $metadata;
+ }
+
+ /**
+ * @param File $image
+ * @param array $metadata
+ * @return bool|int
+ */
+ function isMetadataValid( $image, $metadata ) {
+ global $wgShowEXIF;
+ if ( !$wgShowEXIF ) {
+ # Metadata disabled and so an empty field is expected
+ return self::METADATA_GOOD;
+ }
+ if ( $metadata === self::OLD_BROKEN_FILE ) {
+ # Old special value indicating that there is no Exif data in the file.
+ # or that there was an error well extracting the metadata.
+ wfDebug( __METHOD__ . ": back-compat version\n" );
+
+ return self::METADATA_COMPATIBLE;
+ }
+ if ( $metadata === self::BROKEN_FILE ) {
+ return self::METADATA_GOOD;
+ }
+ Wikimedia\suppressWarnings();
+ $exif = unserialize( $metadata );
+ Wikimedia\restoreWarnings();
+ if ( !isset( $exif['MEDIAWIKI_EXIF_VERSION'] )
+ || $exif['MEDIAWIKI_EXIF_VERSION'] != Exif::version()
+ ) {
+ if ( isset( $exif['MEDIAWIKI_EXIF_VERSION'] )
+ && $exif['MEDIAWIKI_EXIF_VERSION'] == 1
+ ) {
+ // back-compatible but old
+ wfDebug( __METHOD__ . ": back-compat version\n" );
+
+ return self::METADATA_COMPATIBLE;
+ }
+ # Wrong (non-compatible) version
+ wfDebug( __METHOD__ . ": wrong version\n" );
+
+ return self::METADATA_BAD;
+ }
+
+ return self::METADATA_GOOD;
+ }
+
+ /**
+ * @param File $image
+ * @param bool|IContextSource $context Context to use (optional)
+ * @return array|bool
+ */
+ function formatMetadata( $image, $context = false ) {
+ $meta = $this->getCommonMetaArray( $image );
+ if ( count( $meta ) === 0 ) {
+ return false;
+ }
+
+ return $this->formatMetadataHelper( $meta, $context );
+ }
+
+ public function getCommonMetaArray( File $file ) {
+ $metadata = $file->getMetadata();
+ if ( $metadata === self::OLD_BROKEN_FILE
+ || $metadata === self::BROKEN_FILE
+ || $this->isMetadataValid( $file, $metadata ) === self::METADATA_BAD
+ ) {
+ // So we don't try and display metadata from PagedTiffHandler
+ // for example when using InstantCommons.
+ return [];
+ }
+
+ $exif = unserialize( $metadata );
+ if ( !$exif ) {
+ return [];
+ }
+ unset( $exif['MEDIAWIKI_EXIF_VERSION'] );
+
+ return $exif;
+ }
+
+ function getMetadataType( $image ) {
+ return 'exif';
+ }
+
+ /**
+ * Wrapper for base classes ImageHandler::getImageSize() that checks for
+ * rotation reported from metadata and swaps the sizes to match.
+ *
+ * @param File|FSFile $image
+ * @param string $path
+ * @return array
+ */
+ function getImageSize( $image, $path ) {
+ $gis = parent::getImageSize( $image, $path );
+
+ // Don't just call $image->getMetadata(); FSFile::getPropsFromPath() calls us with a bogus object.
+ // This may mean we read EXIF data twice on initial upload.
+ if ( $this->autoRotateEnabled() ) {
+ $meta = $this->getMetadata( $image, $path );
+ $rotation = $this->getRotationForExif( $meta );
+ } else {
+ $rotation = 0;
+ }
+
+ if ( $rotation == 90 || $rotation == 270 ) {
+ $width = $gis[0];
+ $gis[0] = $gis[1];
+ $gis[1] = $width;
+ }
+
+ return $gis;
+ }
+
+ /**
+ * On supporting image formats, try to read out the low-level orientation
+ * of the file and return the angle that the file needs to be rotated to
+ * be viewed.
+ *
+ * This information is only useful when manipulating the original file;
+ * the width and height we normally work with is logical, and will match
+ * any produced output views.
+ *
+ * @param File $file
+ * @return int 0, 90, 180 or 270
+ */
+ public function getRotation( $file ) {
+ if ( !$this->autoRotateEnabled() ) {
+ return 0;
+ }
+
+ $data = $file->getMetadata();
+
+ return $this->getRotationForExif( $data );
+ }
+
+ /**
+ * Given a chunk of serialized Exif metadata, return the orientation as
+ * degrees of rotation.
+ *
+ * @param string $data
+ * @return int 0, 90, 180 or 270
+ * @todo FIXME: Orientation can include flipping as well; see if this is an issue!
+ */
+ protected function getRotationForExif( $data ) {
+ if ( !$data ) {
+ return 0;
+ }
+ Wikimedia\suppressWarnings();
+ $data = unserialize( $data );
+ Wikimedia\restoreWarnings();
+ if ( isset( $data['Orientation'] ) ) {
+ # See http://sylvana.net/jpegcrop/exif_orientation.html
+ switch ( $data['Orientation'] ) {
+ case 8:
+ return 90;
+ case 3:
+ return 180;
+ case 6:
+ return 270;
+ default:
+ return 0;
+ }
+ }
+
+ return 0;
+ }
+}
+++ /dev/null
-<?php
-/**
- * Handler for GIF images.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-/**
- * Handler for GIF images.
- *
- * @ingroup Media
- */
-class GIFHandler extends BitmapHandler {
- const BROKEN_FILE = '0'; // value to store in img_metadata if error extracting metadata.
-
- function getMetadata( $image, $filename ) {
- try {
- $parsedGIFMetadata = BitmapMetadataHandler::GIF( $filename );
- } catch ( Exception $e ) {
- // Broken file?
- wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
-
- return self::BROKEN_FILE;
- }
-
- return serialize( $parsedGIFMetadata );
- }
-
- /**
- * @param File $image
- * @param bool|IContextSource $context Context to use (optional)
- * @return array|bool
- */
- function formatMetadata( $image, $context = false ) {
- $meta = $this->getCommonMetaArray( $image );
- if ( count( $meta ) === 0 ) {
- return false;
- }
-
- return $this->formatMetadataHelper( $meta, $context );
- }
-
- /**
- * Return the standard metadata elements for #filemetadata parser func.
- * @param File $image
- * @return array|bool
- */
- public function getCommonMetaArray( File $image ) {
- $meta = $image->getMetadata();
-
- if ( !$meta ) {
- return [];
- }
- $meta = unserialize( $meta );
- if ( !isset( $meta['metadata'] ) ) {
- return [];
- }
- unset( $meta['metadata']['_MW_GIF_VERSION'] );
-
- return $meta['metadata'];
- }
-
- /**
- * @todo Add unit tests
- *
- * @param File $image
- * @return bool
- */
- function getImageArea( $image ) {
- $ser = $image->getMetadata();
- if ( $ser ) {
- $metadata = unserialize( $ser );
-
- return $image->getWidth() * $image->getHeight() * $metadata['frameCount'];
- } else {
- return $image->getWidth() * $image->getHeight();
- }
- }
-
- /**
- * @param File $image
- * @return bool
- */
- function isAnimatedImage( $image ) {
- $ser = $image->getMetadata();
- if ( $ser ) {
- $metadata = unserialize( $ser );
- if ( $metadata['frameCount'] > 1 ) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * We cannot animate thumbnails that are bigger than a particular size
- * @param File $file
- * @return bool
- */
- function canAnimateThumbnail( $file ) {
- global $wgMaxAnimatedGifArea;
- $answer = $this->getImageArea( $file ) <= $wgMaxAnimatedGifArea;
-
- return $answer;
- }
-
- function getMetadataType( $image ) {
- return 'parsed-gif';
- }
-
- function isMetadataValid( $image, $metadata ) {
- if ( $metadata === self::BROKEN_FILE ) {
- // Do not repetitivly regenerate metadata on broken file.
- return self::METADATA_GOOD;
- }
-
- Wikimedia\suppressWarnings();
- $data = unserialize( $metadata );
- Wikimedia\restoreWarnings();
-
- if ( !$data || !is_array( $data ) ) {
- wfDebug( __METHOD__ . " invalid GIF metadata\n" );
-
- return self::METADATA_BAD;
- }
-
- if ( !isset( $data['metadata']['_MW_GIF_VERSION'] )
- || $data['metadata']['_MW_GIF_VERSION'] != GIFMetadataExtractor::VERSION
- ) {
- wfDebug( __METHOD__ . " old but compatible GIF metadata\n" );
-
- return self::METADATA_COMPATIBLE;
- }
-
- return self::METADATA_GOOD;
- }
-
- /**
- * @param File $image
- * @return string
- */
- function getLongDesc( $image ) {
- global $wgLang;
-
- $original = parent::getLongDesc( $image );
-
- Wikimedia\suppressWarnings();
- $metadata = unserialize( $image->getMetadata() );
- Wikimedia\restoreWarnings();
-
- if ( !$metadata || $metadata['frameCount'] <= 1 ) {
- return $original;
- }
-
- /* Preserve original image info string, but strip the last char ')' so we can add even more */
- $info = [];
- $info[] = $original;
-
- if ( $metadata['looped'] ) {
- $info[] = wfMessage( 'file-info-gif-looped' )->parse();
- }
-
- if ( $metadata['frameCount'] > 1 ) {
- $info[] = wfMessage( 'file-info-gif-frames' )->numParams( $metadata['frameCount'] )->parse();
- }
-
- if ( $metadata['duration'] ) {
- $info[] = $wgLang->formatTimePeriod( $metadata['duration'] );
- }
-
- return $wgLang->commaList( $info );
- }
-
- /**
- * Return the duration of the GIF file.
- *
- * Shown in the &query=imageinfo&iiprop=size api query.
- *
- * @param File $file
- * @return float The duration of the file.
- */
- public function getLength( $file ) {
- $serMeta = $file->getMetadata();
- Wikimedia\suppressWarnings();
- $metadata = unserialize( $serMeta );
- Wikimedia\restoreWarnings();
-
- if ( !$metadata || !isset( $metadata['duration'] ) || !$metadata['duration'] ) {
- return 0.0;
- } else {
- return (float)$metadata['duration'];
- }
- }
-}
--- /dev/null
+<?php
+/**
+ * Handler for GIF images.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * Handler for GIF images.
+ *
+ * @ingroup Media
+ */
+class GIFHandler extends BitmapHandler {
+ const BROKEN_FILE = '0'; // value to store in img_metadata if error extracting metadata.
+
+ function getMetadata( $image, $filename ) {
+ try {
+ $parsedGIFMetadata = BitmapMetadataHandler::GIF( $filename );
+ } catch ( Exception $e ) {
+ // Broken file?
+ wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
+
+ return self::BROKEN_FILE;
+ }
+
+ return serialize( $parsedGIFMetadata );
+ }
+
+ /**
+ * @param File $image
+ * @param bool|IContextSource $context Context to use (optional)
+ * @return array|bool
+ */
+ function formatMetadata( $image, $context = false ) {
+ $meta = $this->getCommonMetaArray( $image );
+ if ( count( $meta ) === 0 ) {
+ return false;
+ }
+
+ return $this->formatMetadataHelper( $meta, $context );
+ }
+
+ /**
+ * Return the standard metadata elements for #filemetadata parser func.
+ * @param File $image
+ * @return array|bool
+ */
+ public function getCommonMetaArray( File $image ) {
+ $meta = $image->getMetadata();
+
+ if ( !$meta ) {
+ return [];
+ }
+ $meta = unserialize( $meta );
+ if ( !isset( $meta['metadata'] ) ) {
+ return [];
+ }
+ unset( $meta['metadata']['_MW_GIF_VERSION'] );
+
+ return $meta['metadata'];
+ }
+
+ /**
+ * @todo Add unit tests
+ *
+ * @param File $image
+ * @return bool
+ */
+ function getImageArea( $image ) {
+ $ser = $image->getMetadata();
+ if ( $ser ) {
+ $metadata = unserialize( $ser );
+
+ return $image->getWidth() * $image->getHeight() * $metadata['frameCount'];
+ } else {
+ return $image->getWidth() * $image->getHeight();
+ }
+ }
+
+ /**
+ * @param File $image
+ * @return bool
+ */
+ function isAnimatedImage( $image ) {
+ $ser = $image->getMetadata();
+ if ( $ser ) {
+ $metadata = unserialize( $ser );
+ if ( $metadata['frameCount'] > 1 ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * We cannot animate thumbnails that are bigger than a particular size
+ * @param File $file
+ * @return bool
+ */
+ function canAnimateThumbnail( $file ) {
+ global $wgMaxAnimatedGifArea;
+ $answer = $this->getImageArea( $file ) <= $wgMaxAnimatedGifArea;
+
+ return $answer;
+ }
+
+ function getMetadataType( $image ) {
+ return 'parsed-gif';
+ }
+
+ function isMetadataValid( $image, $metadata ) {
+ if ( $metadata === self::BROKEN_FILE ) {
+ // Do not repetitivly regenerate metadata on broken file.
+ return self::METADATA_GOOD;
+ }
+
+ Wikimedia\suppressWarnings();
+ $data = unserialize( $metadata );
+ Wikimedia\restoreWarnings();
+
+ if ( !$data || !is_array( $data ) ) {
+ wfDebug( __METHOD__ . " invalid GIF metadata\n" );
+
+ return self::METADATA_BAD;
+ }
+
+ if ( !isset( $data['metadata']['_MW_GIF_VERSION'] )
+ || $data['metadata']['_MW_GIF_VERSION'] != GIFMetadataExtractor::VERSION
+ ) {
+ wfDebug( __METHOD__ . " old but compatible GIF metadata\n" );
+
+ return self::METADATA_COMPATIBLE;
+ }
+
+ return self::METADATA_GOOD;
+ }
+
+ /**
+ * @param File $image
+ * @return string
+ */
+ function getLongDesc( $image ) {
+ global $wgLang;
+
+ $original = parent::getLongDesc( $image );
+
+ Wikimedia\suppressWarnings();
+ $metadata = unserialize( $image->getMetadata() );
+ Wikimedia\restoreWarnings();
+
+ if ( !$metadata || $metadata['frameCount'] <= 1 ) {
+ return $original;
+ }
+
+ /* Preserve original image info string, but strip the last char ')' so we can add even more */
+ $info = [];
+ $info[] = $original;
+
+ if ( $metadata['looped'] ) {
+ $info[] = wfMessage( 'file-info-gif-looped' )->parse();
+ }
+
+ if ( $metadata['frameCount'] > 1 ) {
+ $info[] = wfMessage( 'file-info-gif-frames' )->numParams( $metadata['frameCount'] )->parse();
+ }
+
+ if ( $metadata['duration'] ) {
+ $info[] = $wgLang->formatTimePeriod( $metadata['duration'] );
+ }
+
+ return $wgLang->commaList( $info );
+ }
+
+ /**
+ * Return the duration of the GIF file.
+ *
+ * Shown in the &query=imageinfo&iiprop=size api query.
+ *
+ * @param File $file
+ * @return float The duration of the file.
+ */
+ public function getLength( $file ) {
+ $serMeta = $file->getMetadata();
+ Wikimedia\suppressWarnings();
+ $metadata = unserialize( $serMeta );
+ Wikimedia\restoreWarnings();
+
+ if ( !$metadata || !isset( $metadata['duration'] ) || !$metadata['duration'] ) {
+ return 0.0;
+ } else {
+ return (float)$metadata['duration'];
+ }
+ }
+}
+++ /dev/null
-<?php
-/**
- * Handler for JPEG images.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-/**
- * JPEG specific handler.
- * Inherits most stuff from BitmapHandler, just here to do the metadata handler differently.
- *
- * Metadata stuff common to Jpeg and built-in Tiff (not PagedTiffHandler) is
- * in ExifBitmapHandler.
- *
- * @ingroup Media
- */
-class JpegHandler extends ExifBitmapHandler {
- const SRGB_EXIF_COLOR_SPACE = 'sRGB';
- const SRGB_ICC_PROFILE_DESCRIPTION = 'sRGB IEC61966-2.1';
-
- function normaliseParams( $image, &$params ) {
- if ( !parent::normaliseParams( $image, $params ) ) {
- return false;
- }
- if ( isset( $params['quality'] ) && !self::validateQuality( $params['quality'] ) ) {
- return false;
- }
- return true;
- }
-
- public function validateParam( $name, $value ) {
- if ( $name === 'quality' ) {
- return self::validateQuality( $value );
- } else {
- return parent::validateParam( $name, $value );
- }
- }
-
- /** Validate and normalize quality value to be between 1 and 100 (inclusive).
- * @param int $value Quality value, will be converted to integer or 0 if invalid
- * @return bool True if the value is valid
- */
- private static function validateQuality( $value ) {
- return $value === 'low';
- }
-
- public function makeParamString( $params ) {
- // Prepend quality as "qValue-". This has to match parseParamString() below
- $res = parent::makeParamString( $params );
- if ( $res && isset( $params['quality'] ) ) {
- $res = "q{$params['quality']}-$res";
- }
- return $res;
- }
-
- public function parseParamString( $str ) {
- // $str contains "qlow-200px" or "200px" strings because thumb.php would strip the filename
- // first - check if the string begins with "qlow-", and if so, treat it as quality.
- // Pass the first portion, or the whole string if "qlow-" not found, to the parent
- // The parsing must match the makeParamString() above
- $res = false;
- $m = false;
- if ( preg_match( '/q([^-]+)-(.*)$/', $str, $m ) ) {
- $v = $m[1];
- if ( self::validateQuality( $v ) ) {
- $res = parent::parseParamString( $m[2] );
- if ( $res ) {
- $res['quality'] = $v;
- }
- }
- } else {
- $res = parent::parseParamString( $str );
- }
- return $res;
- }
-
- function getScriptParams( $params ) {
- $res = parent::getScriptParams( $params );
- if ( isset( $params['quality'] ) ) {
- $res['quality'] = $params['quality'];
- }
- return $res;
- }
-
- function getMetadata( $image, $filename ) {
- try {
- $meta = BitmapMetadataHandler::Jpeg( $filename );
- if ( !is_array( $meta ) ) {
- // This should never happen, but doesn't hurt to be paranoid.
- throw new MWException( 'Metadata array is not an array' );
- }
- $meta['MEDIAWIKI_EXIF_VERSION'] = Exif::version();
-
- return serialize( $meta );
- } catch ( Exception $e ) {
- // BitmapMetadataHandler throws an exception in certain exceptional
- // cases like if file does not exist.
- wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
-
- /* This used to use 0 (ExifBitmapHandler::OLD_BROKEN_FILE) for the cases
- * * No metadata in the file
- * * Something is broken in the file.
- * However, if the metadata support gets expanded then you can't tell if the 0 is from
- * a broken file, or just no props found. A broken file is likely to stay broken, but
- * a file which had no props could have props once the metadata support is improved.
- * Thus switch to using -1 to denote only a broken file, and use an array with only
- * MEDIAWIKI_EXIF_VERSION to denote no props.
- */
-
- return ExifBitmapHandler::BROKEN_FILE;
- }
- }
-
- /**
- * @param File $file
- * @param array $params Rotate parameters.
- * 'rotation' clockwise rotation in degrees, allowed are multiples of 90
- * @since 1.21
- * @return bool|MediaTransformError
- */
- public function rotate( $file, $params ) {
- global $wgJpegTran;
-
- $rotation = ( $params['rotation'] + $this->getRotation( $file ) ) % 360;
-
- if ( $wgJpegTran && is_executable( $wgJpegTran ) ) {
- $cmd = wfEscapeShellArg( $wgJpegTran ) .
- " -rotate " . wfEscapeShellArg( $rotation ) .
- " -outfile " . wfEscapeShellArg( $params['dstPath'] ) .
- " " . wfEscapeShellArg( $params['srcPath'] );
- wfDebug( __METHOD__ . ": running jpgtran: $cmd\n" );
- $retval = 0;
- $err = wfShellExecWithStderr( $cmd, $retval );
- if ( $retval !== 0 ) {
- $this->logErrorForExternalProcess( $retval, $err, $cmd );
-
- return new MediaTransformError( 'thumbnail_error', 0, 0, $err );
- }
-
- return false;
- } else {
- return parent::rotate( $file, $params );
- }
- }
-
- public function supportsBucketing() {
- return true;
- }
-
- public function sanitizeParamsForBucketing( $params ) {
- $params = parent::sanitizeParamsForBucketing( $params );
-
- // Quality needs to be cleared for bucketing. Buckets need to be default quality
- if ( isset( $params['quality'] ) ) {
- unset( $params['quality'] );
- }
-
- return $params;
- }
-
- /**
- * @inheritDoc
- */
- protected function transformImageMagick( $image, $params ) {
- global $wgUseTinyRGBForJPGThumbnails;
-
- $ret = parent::transformImageMagick( $image, $params );
-
- if ( $ret ) {
- return $ret;
- }
-
- if ( $wgUseTinyRGBForJPGThumbnails ) {
- // T100976 If the profile embedded in the JPG is sRGB, swap it for the smaller
- // (and free) TinyRGB
-
- /**
- * We'll want to replace the color profile for JPGs:
- * * in the sRGB color space, or with the sRGB profile
- * (other profiles will be left untouched)
- * * without color space or profile, in which case browsers
- * should assume sRGB, but don't always do (e.g. on wide-gamut
- * monitors (unless it's meant for low bandwith)
- * @see https://phabricator.wikimedia.org/T134498
- */
- $colorSpaces = [ self::SRGB_EXIF_COLOR_SPACE, '-' ];
- $profiles = [ self::SRGB_ICC_PROFILE_DESCRIPTION ];
-
- // we'll also add TinyRGB profile to images lacking a profile, but
- // only if they're not low quality (which are meant to save bandwith
- // and we don't want to increase the filesize by adding a profile)
- if ( isset( $params['quality'] ) && $params['quality'] > 30 ) {
- $profiles[] = '-';
- }
-
- $this->swapICCProfile(
- $params['dstPath'],
- $colorSpaces,
- $profiles,
- realpath( __DIR__ ) . '/tinyrgb.icc'
- );
- }
-
- return false;
- }
-
- /**
- * Swaps an embedded ICC profile for another, if found.
- * Depends on exiftool, no-op if not installed.
- * @param string $filepath File to be manipulated (will be overwritten)
- * @param array $colorSpaces Only process files with this/these Color Space(s)
- * @param array $oldProfileStrings Exact name(s) of color profile to look for
- * (the one that will be replaced)
- * @param string $profileFilepath ICC profile file to apply to the file
- * @since 1.26
- * @return bool
- */
- public function swapICCProfile( $filepath, array $colorSpaces,
- array $oldProfileStrings, $profileFilepath
- ) {
- global $wgExiftool;
-
- if ( !$wgExiftool || !is_executable( $wgExiftool ) ) {
- return false;
- }
-
- $cmd = wfEscapeShellArg( $wgExiftool,
- '-EXIF:ColorSpace',
- '-ICC_Profile:ProfileDescription',
- '-S',
- '-T',
- $filepath
- );
-
- $output = wfShellExecWithStderr( $cmd, $retval );
-
- // Explode EXIF data into an array with [0 => Color Space, 1 => Device Model Desc]
- $data = explode( "\t", trim( $output ) );
-
- if ( $retval !== 0 ) {
- return false;
- }
-
- // Make a regex out of the source data to match it to an array of color
- // spaces in a case-insensitive way
- $colorSpaceRegex = '/'.preg_quote( $data[0], '/' ).'/i';
- if ( empty( preg_grep( $colorSpaceRegex, $colorSpaces ) ) ) {
- // We can't establish that this file matches the color space, don't process it
- return false;
- }
-
- $profileRegex = '/'.preg_quote( $data[1], '/' ).'/i';
- if ( empty( preg_grep( $profileRegex, $oldProfileStrings ) ) ) {
- // We can't establish that this file has the expected ICC profile, don't process it
- return false;
- }
-
- $cmd = wfEscapeShellArg( $wgExiftool,
- '-overwrite_original',
- '-icc_profile<=' . $profileFilepath,
- $filepath
- );
-
- $output = wfShellExecWithStderr( $cmd, $retval );
-
- if ( $retval !== 0 ) {
- $this->logErrorForExternalProcess( $retval, $output, $cmd );
-
- return false;
- }
-
- return true;
- }
-}
--- /dev/null
+<?php
+/**
+ * Handler for JPEG images.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * JPEG specific handler.
+ * Inherits most stuff from BitmapHandler, just here to do the metadata handler differently.
+ *
+ * Metadata stuff common to Jpeg and built-in Tiff (not PagedTiffHandler) is
+ * in ExifBitmapHandler.
+ *
+ * @ingroup Media
+ */
+class JpegHandler extends ExifBitmapHandler {
+ const SRGB_EXIF_COLOR_SPACE = 'sRGB';
+ const SRGB_ICC_PROFILE_DESCRIPTION = 'sRGB IEC61966-2.1';
+
+ function normaliseParams( $image, &$params ) {
+ if ( !parent::normaliseParams( $image, $params ) ) {
+ return false;
+ }
+ if ( isset( $params['quality'] ) && !self::validateQuality( $params['quality'] ) ) {
+ return false;
+ }
+ return true;
+ }
+
+ public function validateParam( $name, $value ) {
+ if ( $name === 'quality' ) {
+ return self::validateQuality( $value );
+ } else {
+ return parent::validateParam( $name, $value );
+ }
+ }
+
+ /** Validate and normalize quality value to be between 1 and 100 (inclusive).
+ * @param int $value Quality value, will be converted to integer or 0 if invalid
+ * @return bool True if the value is valid
+ */
+ private static function validateQuality( $value ) {
+ return $value === 'low';
+ }
+
+ public function makeParamString( $params ) {
+ // Prepend quality as "qValue-". This has to match parseParamString() below
+ $res = parent::makeParamString( $params );
+ if ( $res && isset( $params['quality'] ) ) {
+ $res = "q{$params['quality']}-$res";
+ }
+ return $res;
+ }
+
+ public function parseParamString( $str ) {
+ // $str contains "qlow-200px" or "200px" strings because thumb.php would strip the filename
+ // first - check if the string begins with "qlow-", and if so, treat it as quality.
+ // Pass the first portion, or the whole string if "qlow-" not found, to the parent
+ // The parsing must match the makeParamString() above
+ $res = false;
+ $m = false;
+ if ( preg_match( '/q([^-]+)-(.*)$/', $str, $m ) ) {
+ $v = $m[1];
+ if ( self::validateQuality( $v ) ) {
+ $res = parent::parseParamString( $m[2] );
+ if ( $res ) {
+ $res['quality'] = $v;
+ }
+ }
+ } else {
+ $res = parent::parseParamString( $str );
+ }
+ return $res;
+ }
+
+ function getScriptParams( $params ) {
+ $res = parent::getScriptParams( $params );
+ if ( isset( $params['quality'] ) ) {
+ $res['quality'] = $params['quality'];
+ }
+ return $res;
+ }
+
+ function getMetadata( $image, $filename ) {
+ try {
+ $meta = BitmapMetadataHandler::Jpeg( $filename );
+ if ( !is_array( $meta ) ) {
+ // This should never happen, but doesn't hurt to be paranoid.
+ throw new MWException( 'Metadata array is not an array' );
+ }
+ $meta['MEDIAWIKI_EXIF_VERSION'] = Exif::version();
+
+ return serialize( $meta );
+ } catch ( Exception $e ) {
+ // BitmapMetadataHandler throws an exception in certain exceptional
+ // cases like if file does not exist.
+ wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
+
+ /* This used to use 0 (ExifBitmapHandler::OLD_BROKEN_FILE) for the cases
+ * * No metadata in the file
+ * * Something is broken in the file.
+ * However, if the metadata support gets expanded then you can't tell if the 0 is from
+ * a broken file, or just no props found. A broken file is likely to stay broken, but
+ * a file which had no props could have props once the metadata support is improved.
+ * Thus switch to using -1 to denote only a broken file, and use an array with only
+ * MEDIAWIKI_EXIF_VERSION to denote no props.
+ */
+
+ return ExifBitmapHandler::BROKEN_FILE;
+ }
+ }
+
+ /**
+ * @param File $file
+ * @param array $params Rotate parameters.
+ * 'rotation' clockwise rotation in degrees, allowed are multiples of 90
+ * @since 1.21
+ * @return bool|MediaTransformError
+ */
+ public function rotate( $file, $params ) {
+ global $wgJpegTran;
+
+ $rotation = ( $params['rotation'] + $this->getRotation( $file ) ) % 360;
+
+ if ( $wgJpegTran && is_executable( $wgJpegTran ) ) {
+ $cmd = wfEscapeShellArg( $wgJpegTran ) .
+ " -rotate " . wfEscapeShellArg( $rotation ) .
+ " -outfile " . wfEscapeShellArg( $params['dstPath'] ) .
+ " " . wfEscapeShellArg( $params['srcPath'] );
+ wfDebug( __METHOD__ . ": running jpgtran: $cmd\n" );
+ $retval = 0;
+ $err = wfShellExecWithStderr( $cmd, $retval );
+ if ( $retval !== 0 ) {
+ $this->logErrorForExternalProcess( $retval, $err, $cmd );
+
+ return new MediaTransformError( 'thumbnail_error', 0, 0, $err );
+ }
+
+ return false;
+ } else {
+ return parent::rotate( $file, $params );
+ }
+ }
+
+ public function supportsBucketing() {
+ return true;
+ }
+
+ public function sanitizeParamsForBucketing( $params ) {
+ $params = parent::sanitizeParamsForBucketing( $params );
+
+ // Quality needs to be cleared for bucketing. Buckets need to be default quality
+ if ( isset( $params['quality'] ) ) {
+ unset( $params['quality'] );
+ }
+
+ return $params;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function transformImageMagick( $image, $params ) {
+ global $wgUseTinyRGBForJPGThumbnails;
+
+ $ret = parent::transformImageMagick( $image, $params );
+
+ if ( $ret ) {
+ return $ret;
+ }
+
+ if ( $wgUseTinyRGBForJPGThumbnails ) {
+ // T100976 If the profile embedded in the JPG is sRGB, swap it for the smaller
+ // (and free) TinyRGB
+
+ /**
+ * We'll want to replace the color profile for JPGs:
+ * * in the sRGB color space, or with the sRGB profile
+ * (other profiles will be left untouched)
+ * * without color space or profile, in which case browsers
+ * should assume sRGB, but don't always do (e.g. on wide-gamut
+ * monitors (unless it's meant for low bandwith)
+ * @see https://phabricator.wikimedia.org/T134498
+ */
+ $colorSpaces = [ self::SRGB_EXIF_COLOR_SPACE, '-' ];
+ $profiles = [ self::SRGB_ICC_PROFILE_DESCRIPTION ];
+
+ // we'll also add TinyRGB profile to images lacking a profile, but
+ // only if they're not low quality (which are meant to save bandwith
+ // and we don't want to increase the filesize by adding a profile)
+ if ( isset( $params['quality'] ) && $params['quality'] > 30 ) {
+ $profiles[] = '-';
+ }
+
+ $this->swapICCProfile(
+ $params['dstPath'],
+ $colorSpaces,
+ $profiles,
+ realpath( __DIR__ ) . '/tinyrgb.icc'
+ );
+ }
+
+ return false;
+ }
+
+ /**
+ * Swaps an embedded ICC profile for another, if found.
+ * Depends on exiftool, no-op if not installed.
+ * @param string $filepath File to be manipulated (will be overwritten)
+ * @param array $colorSpaces Only process files with this/these Color Space(s)
+ * @param array $oldProfileStrings Exact name(s) of color profile to look for
+ * (the one that will be replaced)
+ * @param string $profileFilepath ICC profile file to apply to the file
+ * @since 1.26
+ * @return bool
+ */
+ public function swapICCProfile( $filepath, array $colorSpaces,
+ array $oldProfileStrings, $profileFilepath
+ ) {
+ global $wgExiftool;
+
+ if ( !$wgExiftool || !is_executable( $wgExiftool ) ) {
+ return false;
+ }
+
+ $cmd = wfEscapeShellArg( $wgExiftool,
+ '-EXIF:ColorSpace',
+ '-ICC_Profile:ProfileDescription',
+ '-S',
+ '-T',
+ $filepath
+ );
+
+ $output = wfShellExecWithStderr( $cmd, $retval );
+
+ // Explode EXIF data into an array with [0 => Color Space, 1 => Device Model Desc]
+ $data = explode( "\t", trim( $output ) );
+
+ if ( $retval !== 0 ) {
+ return false;
+ }
+
+ // Make a regex out of the source data to match it to an array of color
+ // spaces in a case-insensitive way
+ $colorSpaceRegex = '/'.preg_quote( $data[0], '/' ).'/i';
+ if ( empty( preg_grep( $colorSpaceRegex, $colorSpaces ) ) ) {
+ // We can't establish that this file matches the color space, don't process it
+ return false;
+ }
+
+ $profileRegex = '/'.preg_quote( $data[1], '/' ).'/i';
+ if ( empty( preg_grep( $profileRegex, $oldProfileStrings ) ) ) {
+ // We can't establish that this file has the expected ICC profile, don't process it
+ return false;
+ }
+
+ $cmd = wfEscapeShellArg( $wgExiftool,
+ '-overwrite_original',
+ '-icc_profile<=' . $profileFilepath,
+ $filepath
+ );
+
+ $output = wfShellExecWithStderr( $cmd, $retval );
+
+ if ( $retval !== 0 ) {
+ $this->logErrorForExternalProcess( $retval, $output, $cmd );
+
+ return false;
+ }
+
+ return true;
+ }
+}
+++ /dev/null
-<?php
-/**
- * Handler for PNG images.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-/**
- * Handler for PNG images.
- *
- * @ingroup Media
- */
-class PNGHandler extends BitmapHandler {
- const BROKEN_FILE = '0';
-
- /**
- * @param File|FSFile $image
- * @param string $filename
- * @return string
- */
- function getMetadata( $image, $filename ) {
- try {
- $metadata = BitmapMetadataHandler::PNG( $filename );
- } catch ( Exception $e ) {
- // Broken file?
- wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
-
- return self::BROKEN_FILE;
- }
-
- return serialize( $metadata );
- }
-
- /**
- * @param File $image
- * @param bool|IContextSource $context Context to use (optional)
- * @return array|bool
- */
- function formatMetadata( $image, $context = false ) {
- $meta = $this->getCommonMetaArray( $image );
- if ( count( $meta ) === 0 ) {
- return false;
- }
-
- return $this->formatMetadataHelper( $meta, $context );
- }
-
- /**
- * Get a file type independent array of metadata.
- *
- * @param File $image
- * @return array The metadata array
- */
- public function getCommonMetaArray( File $image ) {
- $meta = $image->getMetadata();
-
- if ( !$meta ) {
- return [];
- }
- $meta = unserialize( $meta );
- if ( !isset( $meta['metadata'] ) ) {
- return [];
- }
- unset( $meta['metadata']['_MW_PNG_VERSION'] );
-
- return $meta['metadata'];
- }
-
- /**
- * @param File $image
- * @return bool
- */
- function isAnimatedImage( $image ) {
- $ser = $image->getMetadata();
- if ( $ser ) {
- $metadata = unserialize( $ser );
- if ( $metadata['frameCount'] > 1 ) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * We do not support making APNG thumbnails, so always false
- * @param File $image
- * @return bool False
- */
- function canAnimateThumbnail( $image ) {
- return false;
- }
-
- function getMetadataType( $image ) {
- return 'parsed-png';
- }
-
- function isMetadataValid( $image, $metadata ) {
- if ( $metadata === self::BROKEN_FILE ) {
- // Do not repetitivly regenerate metadata on broken file.
- return self::METADATA_GOOD;
- }
-
- Wikimedia\suppressWarnings();
- $data = unserialize( $metadata );
- Wikimedia\restoreWarnings();
-
- if ( !$data || !is_array( $data ) ) {
- wfDebug( __METHOD__ . " invalid png metadata\n" );
-
- return self::METADATA_BAD;
- }
-
- if ( !isset( $data['metadata']['_MW_PNG_VERSION'] )
- || $data['metadata']['_MW_PNG_VERSION'] != PNGMetadataExtractor::VERSION
- ) {
- wfDebug( __METHOD__ . " old but compatible png metadata\n" );
-
- return self::METADATA_COMPATIBLE;
- }
-
- return self::METADATA_GOOD;
- }
-
- /**
- * @param File $image
- * @return string
- */
- function getLongDesc( $image ) {
- global $wgLang;
- $original = parent::getLongDesc( $image );
-
- Wikimedia\suppressWarnings();
- $metadata = unserialize( $image->getMetadata() );
- Wikimedia\restoreWarnings();
-
- if ( !$metadata || $metadata['frameCount'] <= 0 ) {
- return $original;
- }
-
- $info = [];
- $info[] = $original;
-
- if ( $metadata['loopCount'] == 0 ) {
- $info[] = wfMessage( 'file-info-png-looped' )->parse();
- } elseif ( $metadata['loopCount'] > 1 ) {
- $info[] = wfMessage( 'file-info-png-repeat' )->numParams( $metadata['loopCount'] )->parse();
- }
-
- if ( $metadata['frameCount'] > 0 ) {
- $info[] = wfMessage( 'file-info-png-frames' )->numParams( $metadata['frameCount'] )->parse();
- }
-
- if ( $metadata['duration'] ) {
- $info[] = $wgLang->formatTimePeriod( $metadata['duration'] );
- }
-
- return $wgLang->commaList( $info );
- }
-
- /**
- * Return the duration of an APNG file.
- *
- * Shown in the &query=imageinfo&iiprop=size api query.
- *
- * @param File $file
- * @return float The duration of the file.
- */
- public function getLength( $file ) {
- $serMeta = $file->getMetadata();
- Wikimedia\suppressWarnings();
- $metadata = unserialize( $serMeta );
- Wikimedia\restoreWarnings();
-
- if ( !$metadata || !isset( $metadata['duration'] ) || !$metadata['duration'] ) {
- return 0.0;
- } else {
- return (float)$metadata['duration'];
- }
- }
-
- // PNGs should be easy to support, but it will need some sharpening applied
- // and another user test to check if the perceived quality change is noticeable
- public function supportsBucketing() {
- return false;
- }
-}
--- /dev/null
+<?php
+/**
+ * Handler for PNG images.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * Handler for PNG images.
+ *
+ * @ingroup Media
+ */
+class PNGHandler extends BitmapHandler {
+ const BROKEN_FILE = '0';
+
+ /**
+ * @param File|FSFile $image
+ * @param string $filename
+ * @return string
+ */
+ function getMetadata( $image, $filename ) {
+ try {
+ $metadata = BitmapMetadataHandler::PNG( $filename );
+ } catch ( Exception $e ) {
+ // Broken file?
+ wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
+
+ return self::BROKEN_FILE;
+ }
+
+ return serialize( $metadata );
+ }
+
+ /**
+ * @param File $image
+ * @param bool|IContextSource $context Context to use (optional)
+ * @return array|bool
+ */
+ function formatMetadata( $image, $context = false ) {
+ $meta = $this->getCommonMetaArray( $image );
+ if ( count( $meta ) === 0 ) {
+ return false;
+ }
+
+ return $this->formatMetadataHelper( $meta, $context );
+ }
+
+ /**
+ * Get a file type independent array of metadata.
+ *
+ * @param File $image
+ * @return array The metadata array
+ */
+ public function getCommonMetaArray( File $image ) {
+ $meta = $image->getMetadata();
+
+ if ( !$meta ) {
+ return [];
+ }
+ $meta = unserialize( $meta );
+ if ( !isset( $meta['metadata'] ) ) {
+ return [];
+ }
+ unset( $meta['metadata']['_MW_PNG_VERSION'] );
+
+ return $meta['metadata'];
+ }
+
+ /**
+ * @param File $image
+ * @return bool
+ */
+ function isAnimatedImage( $image ) {
+ $ser = $image->getMetadata();
+ if ( $ser ) {
+ $metadata = unserialize( $ser );
+ if ( $metadata['frameCount'] > 1 ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * We do not support making APNG thumbnails, so always false
+ * @param File $image
+ * @return bool False
+ */
+ function canAnimateThumbnail( $image ) {
+ return false;
+ }
+
+ function getMetadataType( $image ) {
+ return 'parsed-png';
+ }
+
+ function isMetadataValid( $image, $metadata ) {
+ if ( $metadata === self::BROKEN_FILE ) {
+ // Do not repetitivly regenerate metadata on broken file.
+ return self::METADATA_GOOD;
+ }
+
+ Wikimedia\suppressWarnings();
+ $data = unserialize( $metadata );
+ Wikimedia\restoreWarnings();
+
+ if ( !$data || !is_array( $data ) ) {
+ wfDebug( __METHOD__ . " invalid png metadata\n" );
+
+ return self::METADATA_BAD;
+ }
+
+ if ( !isset( $data['metadata']['_MW_PNG_VERSION'] )
+ || $data['metadata']['_MW_PNG_VERSION'] != PNGMetadataExtractor::VERSION
+ ) {
+ wfDebug( __METHOD__ . " old but compatible png metadata\n" );
+
+ return self::METADATA_COMPATIBLE;
+ }
+
+ return self::METADATA_GOOD;
+ }
+
+ /**
+ * @param File $image
+ * @return string
+ */
+ function getLongDesc( $image ) {
+ global $wgLang;
+ $original = parent::getLongDesc( $image );
+
+ Wikimedia\suppressWarnings();
+ $metadata = unserialize( $image->getMetadata() );
+ Wikimedia\restoreWarnings();
+
+ if ( !$metadata || $metadata['frameCount'] <= 0 ) {
+ return $original;
+ }
+
+ $info = [];
+ $info[] = $original;
+
+ if ( $metadata['loopCount'] == 0 ) {
+ $info[] = wfMessage( 'file-info-png-looped' )->parse();
+ } elseif ( $metadata['loopCount'] > 1 ) {
+ $info[] = wfMessage( 'file-info-png-repeat' )->numParams( $metadata['loopCount'] )->parse();
+ }
+
+ if ( $metadata['frameCount'] > 0 ) {
+ $info[] = wfMessage( 'file-info-png-frames' )->numParams( $metadata['frameCount'] )->parse();
+ }
+
+ if ( $metadata['duration'] ) {
+ $info[] = $wgLang->formatTimePeriod( $metadata['duration'] );
+ }
+
+ return $wgLang->commaList( $info );
+ }
+
+ /**
+ * Return the duration of an APNG file.
+ *
+ * Shown in the &query=imageinfo&iiprop=size api query.
+ *
+ * @param File $file
+ * @return float The duration of the file.
+ */
+ public function getLength( $file ) {
+ $serMeta = $file->getMetadata();
+ Wikimedia\suppressWarnings();
+ $metadata = unserialize( $serMeta );
+ Wikimedia\restoreWarnings();
+
+ if ( !$metadata || !isset( $metadata['duration'] ) || !$metadata['duration'] ) {
+ return 0.0;
+ } else {
+ return (float)$metadata['duration'];
+ }
+ }
+
+ // PNGs should be easy to support, but it will need some sharpening applied
+ // and another user test to check if the perceived quality change is noticeable
+ public function supportsBucketing() {
+ return false;
+ }
+}
+++ /dev/null
-<?php
-/**
- * Handler for SVG images.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-use Wikimedia\ScopedCallback;
-
-/**
- * Handler for SVG images.
- *
- * @ingroup Media
- */
-class SvgHandler extends ImageHandler {
- const SVG_METADATA_VERSION = 2;
-
- /** @var array A list of metadata tags that can be converted
- * to the commonly used exif tags. This allows messages
- * to be reused, and consistent tag names for {{#formatmetadata:..}}
- */
- private static $metaConversion = [
- 'originalwidth' => 'ImageWidth',
- 'originalheight' => 'ImageLength',
- 'description' => 'ImageDescription',
- 'title' => 'ObjectName',
- ];
-
- function isEnabled() {
- global $wgSVGConverters, $wgSVGConverter;
- if ( !isset( $wgSVGConverters[$wgSVGConverter] ) ) {
- wfDebug( "\$wgSVGConverter is invalid, disabling SVG rendering.\n" );
-
- return false;
- } else {
- return true;
- }
- }
-
- public function mustRender( $file ) {
- return true;
- }
-
- function isVectorized( $file ) {
- return true;
- }
-
- /**
- * @param File $file
- * @return bool
- */
- function isAnimatedImage( $file ) {
- # @todo Detect animated SVGs
- $metadata = $file->getMetadata();
- if ( $metadata ) {
- $metadata = $this->unpackMetadata( $metadata );
- if ( isset( $metadata['animated'] ) ) {
- return $metadata['animated'];
- }
- }
-
- return false;
- }
-
- /**
- * Which languages (systemLanguage attribute) is supported.
- *
- * @note This list is not guaranteed to be exhaustive.
- * To avoid OOM errors, we only look at first bit of a file.
- * Thus all languages on this list are present in the file,
- * but its possible for the file to have a language not on
- * this list.
- *
- * @param File $file
- * @return array Array of language codes, or empty if no language switching supported.
- */
- public function getAvailableLanguages( File $file ) {
- $metadata = $file->getMetadata();
- $langList = [];
- if ( $metadata ) {
- $metadata = $this->unpackMetadata( $metadata );
- if ( isset( $metadata['translations'] ) ) {
- foreach ( $metadata['translations'] as $lang => $langType ) {
- if ( $langType === SVGReader::LANG_FULL_MATCH ) {
- $langList[] = strtolower( $lang );
- }
- }
- }
- }
- return array_unique( $langList );
- }
-
- /**
- * SVG's systemLanguage matching rules state:
- * 'The `systemLanguage` attribute ... [e]valuates to "true" if one of the languages indicated
- * by user preferences exactly equals one of the languages given in the value of this parameter,
- * or if one of the languages indicated by user preferences exactly equals a prefix of one of
- * the languages given in the value of this parameter such that the first tag character
- * following the prefix is "-".'
- *
- * Return the first element of $svgLanguages that matches $userPreferredLanguage
- *
- * @see https://www.w3.org/TR/SVG/struct.html#SystemLanguageAttribute
- * @param string $userPreferredLanguage
- * @param array $svgLanguages
- * @return string|null
- */
- public function getMatchedLanguage( $userPreferredLanguage, array $svgLanguages ) {
- foreach ( $svgLanguages as $svgLang ) {
- if ( strcasecmp( $svgLang, $userPreferredLanguage ) === 0 ) {
- return $svgLang;
- }
- $trimmedSvgLang = $svgLang;
- while ( strpos( $trimmedSvgLang, '-' ) !== false ) {
- $trimmedSvgLang = substr( $trimmedSvgLang, 0, strrpos( $trimmedSvgLang, '-' ) );
- if ( strcasecmp( $trimmedSvgLang, $userPreferredLanguage ) === 0 ) {
- return $svgLang;
- }
- }
- }
- return null;
- }
-
- /**
- * What language to render file in if none selected
- *
- * @param File $file Language code
- * @return string
- */
- public function getDefaultRenderLanguage( File $file ) {
- return 'en';
- }
-
- /**
- * We do not support making animated svg thumbnails
- * @param File $file
- * @return bool
- */
- function canAnimateThumbnail( $file ) {
- return false;
- }
-
- /**
- * @param File $image
- * @param array &$params
- * @return bool
- */
- function normaliseParams( $image, &$params ) {
- global $wgSVGMaxSize;
- if ( !parent::normaliseParams( $image, $params ) ) {
- return false;
- }
- # Don't make an image bigger than wgMaxSVGSize on the smaller side
- if ( $params['physicalWidth'] <= $params['physicalHeight'] ) {
- if ( $params['physicalWidth'] > $wgSVGMaxSize ) {
- $srcWidth = $image->getWidth( $params['page'] );
- $srcHeight = $image->getHeight( $params['page'] );
- $params['physicalWidth'] = $wgSVGMaxSize;
- $params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight, $wgSVGMaxSize );
- }
- } else {
- if ( $params['physicalHeight'] > $wgSVGMaxSize ) {
- $srcWidth = $image->getWidth( $params['page'] );
- $srcHeight = $image->getHeight( $params['page'] );
- $params['physicalWidth'] = File::scaleHeight( $srcHeight, $srcWidth, $wgSVGMaxSize );
- $params['physicalHeight'] = $wgSVGMaxSize;
- }
- }
-
- return true;
- }
-
- /**
- * @param File $image
- * @param string $dstPath
- * @param string $dstUrl
- * @param array $params
- * @param int $flags
- * @return bool|MediaTransformError|ThumbnailImage|TransformParameterError
- */
- function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
- if ( !$this->normaliseParams( $image, $params ) ) {
- return new TransformParameterError( $params );
- }
- $clientWidth = $params['width'];
- $clientHeight = $params['height'];
- $physicalWidth = $params['physicalWidth'];
- $physicalHeight = $params['physicalHeight'];
- $lang = isset( $params['lang'] ) ? $params['lang'] : $this->getDefaultRenderLanguage( $image );
-
- if ( $flags & self::TRANSFORM_LATER ) {
- return new ThumbnailImage( $image, $dstUrl, $dstPath, $params );
- }
-
- $metadata = $this->unpackMetadata( $image->getMetadata() );
- if ( isset( $metadata['error'] ) ) { // sanity check
- $err = wfMessage( 'svg-long-error', $metadata['error']['message'] );
-
- return new MediaTransformError( 'thumbnail_error', $clientWidth, $clientHeight, $err );
- }
-
- if ( !wfMkdirParents( dirname( $dstPath ), null, __METHOD__ ) ) {
- return new MediaTransformError( 'thumbnail_error', $clientWidth, $clientHeight,
- wfMessage( 'thumbnail_dest_directory' ) );
- }
-
- $srcPath = $image->getLocalRefPath();
- if ( $srcPath === false ) { // Failed to get local copy
- wfDebugLog( 'thumbnail',
- sprintf( 'Thumbnail failed on %s: could not get local copy of "%s"',
- wfHostname(), $image->getName() ) );
-
- return new MediaTransformError( 'thumbnail_error',
- $params['width'], $params['height'],
- wfMessage( 'filemissing' )
- );
- }
-
- // Make a temp dir with a symlink to the local copy in it.
- // This plays well with rsvg-convert policy for external entities.
- // https://git.gnome.org/browse/librsvg/commit/?id=f01aded72c38f0e18bc7ff67dee800e380251c8e
- $tmpDir = wfTempDir() . '/svg_' . wfRandomString( 24 );
- $lnPath = "$tmpDir/" . basename( $srcPath );
- $ok = mkdir( $tmpDir, 0771 );
- if ( !$ok ) {
- wfDebugLog( 'thumbnail',
- sprintf( 'Thumbnail failed on %s: could not create temporary directory %s',
- wfHostname(), $tmpDir ) );
- return new MediaTransformError( 'thumbnail_error',
- $params['width'], $params['height'],
- wfMessage( 'thumbnail-temp-create' )->text()
- );
- }
- $ok = symlink( $srcPath, $lnPath );
- /** @noinspection PhpUnusedLocalVariableInspection */
- $cleaner = new ScopedCallback( function () use ( $tmpDir, $lnPath ) {
- Wikimedia\suppressWarnings();
- unlink( $lnPath );
- rmdir( $tmpDir );
- Wikimedia\restoreWarnings();
- } );
- if ( !$ok ) {
- wfDebugLog( 'thumbnail',
- sprintf( 'Thumbnail failed on %s: could not link %s to %s',
- wfHostname(), $lnPath, $srcPath ) );
- return new MediaTransformError( 'thumbnail_error',
- $params['width'], $params['height'],
- wfMessage( 'thumbnail-temp-create' )
- );
- }
-
- $status = $this->rasterize( $lnPath, $dstPath, $physicalWidth, $physicalHeight, $lang );
- if ( $status === true ) {
- return new ThumbnailImage( $image, $dstUrl, $dstPath, $params );
- } else {
- return $status; // MediaTransformError
- }
- }
-
- /**
- * Transform an SVG file to PNG
- * This function can be called outside of thumbnail contexts
- * @param string $srcPath
- * @param string $dstPath
- * @param string $width
- * @param string $height
- * @param bool|string $lang Language code of the language to render the SVG in
- * @throws MWException
- * @return bool|MediaTransformError
- */
- public function rasterize( $srcPath, $dstPath, $width, $height, $lang = false ) {
- global $wgSVGConverters, $wgSVGConverter, $wgSVGConverterPath;
- $err = false;
- $retval = '';
- if ( isset( $wgSVGConverters[$wgSVGConverter] ) ) {
- if ( is_array( $wgSVGConverters[$wgSVGConverter] ) ) {
- // This is a PHP callable
- $func = $wgSVGConverters[$wgSVGConverter][0];
- $args = array_merge( [ $srcPath, $dstPath, $width, $height, $lang ],
- array_slice( $wgSVGConverters[$wgSVGConverter], 1 ) );
- if ( !is_callable( $func ) ) {
- throw new MWException( "$func is not callable" );
- }
- $err = call_user_func_array( $func, $args );
- $retval = (bool)$err;
- } else {
- // External command
- $cmd = str_replace(
- [ '$path/', '$width', '$height', '$input', '$output' ],
- [ $wgSVGConverterPath ? wfEscapeShellArg( "$wgSVGConverterPath/" ) : "",
- intval( $width ),
- intval( $height ),
- wfEscapeShellArg( $srcPath ),
- wfEscapeShellArg( $dstPath ) ],
- $wgSVGConverters[$wgSVGConverter]
- );
-
- $env = [];
- if ( $lang !== false ) {
- $env['LANG'] = $lang;
- }
-
- wfDebug( __METHOD__ . ": $cmd\n" );
- $err = wfShellExecWithStderr( $cmd, $retval, $env );
- }
- }
- $removed = $this->removeBadFile( $dstPath, $retval );
- if ( $retval != 0 || $removed ) {
- $this->logErrorForExternalProcess( $retval, $err, $cmd );
- return new MediaTransformError( 'thumbnail_error', $width, $height, $err );
- }
-
- return true;
- }
-
- public static function rasterizeImagickExt( $srcPath, $dstPath, $width, $height ) {
- $im = new Imagick( $srcPath );
- $im->setImageFormat( 'png' );
- $im->setBackgroundColor( 'transparent' );
- $im->setImageDepth( 8 );
-
- if ( !$im->thumbnailImage( intval( $width ), intval( $height ), /* fit */ false ) ) {
- return 'Could not resize image';
- }
- if ( !$im->writeImage( $dstPath ) ) {
- return "Could not write to $dstPath";
- }
- }
-
- /**
- * @param File|FSFile $file
- * @param string $path Unused
- * @param bool|array $metadata
- * @return array
- */
- function getImageSize( $file, $path, $metadata = false ) {
- if ( $metadata === false && $file instanceof File ) {
- $metadata = $file->getMetadata();
- }
- $metadata = $this->unpackMetadata( $metadata );
-
- if ( isset( $metadata['width'] ) && isset( $metadata['height'] ) ) {
- return [ $metadata['width'], $metadata['height'], 'SVG',
- "width=\"{$metadata['width']}\" height=\"{$metadata['height']}\"" ];
- } else { // error
- return [ 0, 0, 'SVG', "width=\"0\" height=\"0\"" ];
- }
- }
-
- function getThumbType( $ext, $mime, $params = null ) {
- return [ 'png', 'image/png' ];
- }
-
- /**
- * Subtitle for the image. Different from the base
- * class so it can be denoted that SVG's have
- * a "nominal" resolution, and not a fixed one,
- * as well as so animation can be denoted.
- *
- * @param File $file
- * @return string
- */
- function getLongDesc( $file ) {
- global $wgLang;
-
- $metadata = $this->unpackMetadata( $file->getMetadata() );
- if ( isset( $metadata['error'] ) ) {
- return wfMessage( 'svg-long-error', $metadata['error']['message'] )->text();
- }
-
- $size = $wgLang->formatSize( $file->getSize() );
-
- if ( $this->isAnimatedImage( $file ) ) {
- $msg = wfMessage( 'svg-long-desc-animated' );
- } else {
- $msg = wfMessage( 'svg-long-desc' );
- }
-
- $msg->numParams( $file->getWidth(), $file->getHeight() )->params( $size );
-
- return $msg->parse();
- }
-
- /**
- * @param File|FSFile $file
- * @param string $filename
- * @return string Serialised metadata
- */
- function getMetadata( $file, $filename ) {
- $metadata = [ 'version' => self::SVG_METADATA_VERSION ];
- try {
- $metadata += SVGMetadataExtractor::getMetadata( $filename );
- } catch ( Exception $e ) { // @todo SVG specific exceptions
- // File not found, broken, etc.
- $metadata['error'] = [
- 'message' => $e->getMessage(),
- 'code' => $e->getCode()
- ];
- wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
- }
-
- return serialize( $metadata );
- }
-
- function unpackMetadata( $metadata ) {
- Wikimedia\suppressWarnings();
- $unser = unserialize( $metadata );
- Wikimedia\restoreWarnings();
- if ( isset( $unser['version'] ) && $unser['version'] == self::SVG_METADATA_VERSION ) {
- return $unser;
- } else {
- return false;
- }
- }
-
- function getMetadataType( $image ) {
- return 'parsed-svg';
- }
-
- function isMetadataValid( $image, $metadata ) {
- $meta = $this->unpackMetadata( $metadata );
- if ( $meta === false ) {
- return self::METADATA_BAD;
- }
- if ( !isset( $meta['originalWidth'] ) ) {
- // Old but compatible
- return self::METADATA_COMPATIBLE;
- }
-
- return self::METADATA_GOOD;
- }
-
- protected function visibleMetadataFields() {
- $fields = [ 'objectname', 'imagedescription' ];
-
- return $fields;
- }
-
- /**
- * @param File $file
- * @param bool|IContextSource $context Context to use (optional)
- * @return array|bool
- */
- function formatMetadata( $file, $context = false ) {
- $result = [
- 'visible' => [],
- 'collapsed' => []
- ];
- $metadata = $file->getMetadata();
- if ( !$metadata ) {
- return false;
- }
- $metadata = $this->unpackMetadata( $metadata );
- if ( !$metadata || isset( $metadata['error'] ) ) {
- return false;
- }
-
- /* @todo Add a formatter
- $format = new FormatSVG( $metadata );
- $formatted = $format->getFormattedData();
- */
-
- // Sort fields into visible and collapsed
- $visibleFields = $this->visibleMetadataFields();
-
- $showMeta = false;
- foreach ( $metadata as $name => $value ) {
- $tag = strtolower( $name );
- if ( isset( self::$metaConversion[$tag] ) ) {
- $tag = strtolower( self::$metaConversion[$tag] );
- } else {
- // Do not output other metadata not in list
- continue;
- }
- $showMeta = true;
- self::addMeta( $result,
- in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed',
- 'exif',
- $tag,
- $value
- );
- }
-
- return $showMeta ? $result : false;
- }
-
- /**
- * @param string $name Parameter name
- * @param mixed $value Parameter value
- * @return bool Validity
- */
- public function validateParam( $name, $value ) {
- if ( in_array( $name, [ 'width', 'height' ] ) ) {
- // Reject negative heights, widths
- return ( $value > 0 );
- } elseif ( $name == 'lang' ) {
- // Validate $code
- if ( $value === '' || !Language::isValidCode( $value ) ) {
- return false;
- }
-
- return true;
- }
-
- // Only lang, width and height are acceptable keys
- return false;
- }
-
- /**
- * @param array $params Name=>value pairs of parameters
- * @return string Filename to use
- */
- public function makeParamString( $params ) {
- $lang = '';
- if ( isset( $params['lang'] ) && $params['lang'] !== 'en' ) {
- $lang = 'lang' . strtolower( $params['lang'] ) . '-';
- }
- if ( !isset( $params['width'] ) ) {
- return false;
- }
-
- return "$lang{$params['width']}px";
- }
-
- public function parseParamString( $str ) {
- $m = false;
- if ( preg_match( '/^lang([a-z]+(?:-[a-z]+)*)-(\d+)px$/i', $str, $m ) ) {
- return [ 'width' => array_pop( $m ), 'lang' => $m[1] ];
- } elseif ( preg_match( '/^(\d+)px$/', $str, $m ) ) {
- return [ 'width' => $m[1], 'lang' => 'en' ];
- } else {
- return false;
- }
- }
-
- public function getParamMap() {
- return [ 'img_lang' => 'lang', 'img_width' => 'width' ];
- }
-
- /**
- * @param array $params
- * @return array
- */
- function getScriptParams( $params ) {
- $scriptParams = [ 'width' => $params['width'] ];
- if ( isset( $params['lang'] ) ) {
- $scriptParams['lang'] = $params['lang'];
- }
-
- return $scriptParams;
- }
-
- public function getCommonMetaArray( File $file ) {
- $metadata = $file->getMetadata();
- if ( !$metadata ) {
- return [];
- }
- $metadata = $this->unpackMetadata( $metadata );
- if ( !$metadata || isset( $metadata['error'] ) ) {
- return [];
- }
- $stdMetadata = [];
- foreach ( $metadata as $name => $value ) {
- $tag = strtolower( $name );
- if ( $tag === 'originalwidth' || $tag === 'originalheight' ) {
- // Skip these. In the exif metadata stuff, it is assumed these
- // are measured in px, which is not the case here.
- continue;
- }
- if ( isset( self::$metaConversion[$tag] ) ) {
- $tag = self::$metaConversion[$tag];
- $stdMetadata[$tag] = $value;
- }
- }
-
- return $stdMetadata;
- }
-}
--- /dev/null
+<?php
+/**
+ * Handler for SVG images.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+use Wikimedia\ScopedCallback;
+
+/**
+ * Handler for SVG images.
+ *
+ * @ingroup Media
+ */
+class SvgHandler extends ImageHandler {
+ const SVG_METADATA_VERSION = 2;
+
+ /** @var array A list of metadata tags that can be converted
+ * to the commonly used exif tags. This allows messages
+ * to be reused, and consistent tag names for {{#formatmetadata:..}}
+ */
+ private static $metaConversion = [
+ 'originalwidth' => 'ImageWidth',
+ 'originalheight' => 'ImageLength',
+ 'description' => 'ImageDescription',
+ 'title' => 'ObjectName',
+ ];
+
+ function isEnabled() {
+ global $wgSVGConverters, $wgSVGConverter;
+ if ( !isset( $wgSVGConverters[$wgSVGConverter] ) ) {
+ wfDebug( "\$wgSVGConverter is invalid, disabling SVG rendering.\n" );
+
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public function mustRender( $file ) {
+ return true;
+ }
+
+ function isVectorized( $file ) {
+ return true;
+ }
+
+ /**
+ * @param File $file
+ * @return bool
+ */
+ function isAnimatedImage( $file ) {
+ # @todo Detect animated SVGs
+ $metadata = $file->getMetadata();
+ if ( $metadata ) {
+ $metadata = $this->unpackMetadata( $metadata );
+ if ( isset( $metadata['animated'] ) ) {
+ return $metadata['animated'];
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Which languages (systemLanguage attribute) is supported.
+ *
+ * @note This list is not guaranteed to be exhaustive.
+ * To avoid OOM errors, we only look at first bit of a file.
+ * Thus all languages on this list are present in the file,
+ * but its possible for the file to have a language not on
+ * this list.
+ *
+ * @param File $file
+ * @return array Array of language codes, or empty if no language switching supported.
+ */
+ public function getAvailableLanguages( File $file ) {
+ $metadata = $file->getMetadata();
+ $langList = [];
+ if ( $metadata ) {
+ $metadata = $this->unpackMetadata( $metadata );
+ if ( isset( $metadata['translations'] ) ) {
+ foreach ( $metadata['translations'] as $lang => $langType ) {
+ if ( $langType === SVGReader::LANG_FULL_MATCH ) {
+ $langList[] = strtolower( $lang );
+ }
+ }
+ }
+ }
+ return array_unique( $langList );
+ }
+
+ /**
+ * SVG's systemLanguage matching rules state:
+ * 'The `systemLanguage` attribute ... [e]valuates to "true" if one of the languages indicated
+ * by user preferences exactly equals one of the languages given in the value of this parameter,
+ * or if one of the languages indicated by user preferences exactly equals a prefix of one of
+ * the languages given in the value of this parameter such that the first tag character
+ * following the prefix is "-".'
+ *
+ * Return the first element of $svgLanguages that matches $userPreferredLanguage
+ *
+ * @see https://www.w3.org/TR/SVG/struct.html#SystemLanguageAttribute
+ * @param string $userPreferredLanguage
+ * @param array $svgLanguages
+ * @return string|null
+ */
+ public function getMatchedLanguage( $userPreferredLanguage, array $svgLanguages ) {
+ foreach ( $svgLanguages as $svgLang ) {
+ if ( strcasecmp( $svgLang, $userPreferredLanguage ) === 0 ) {
+ return $svgLang;
+ }
+ $trimmedSvgLang = $svgLang;
+ while ( strpos( $trimmedSvgLang, '-' ) !== false ) {
+ $trimmedSvgLang = substr( $trimmedSvgLang, 0, strrpos( $trimmedSvgLang, '-' ) );
+ if ( strcasecmp( $trimmedSvgLang, $userPreferredLanguage ) === 0 ) {
+ return $svgLang;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * What language to render file in if none selected
+ *
+ * @param File $file Language code
+ * @return string
+ */
+ public function getDefaultRenderLanguage( File $file ) {
+ return 'en';
+ }
+
+ /**
+ * We do not support making animated svg thumbnails
+ * @param File $file
+ * @return bool
+ */
+ function canAnimateThumbnail( $file ) {
+ return false;
+ }
+
+ /**
+ * @param File $image
+ * @param array &$params
+ * @return bool
+ */
+ function normaliseParams( $image, &$params ) {
+ global $wgSVGMaxSize;
+ if ( !parent::normaliseParams( $image, $params ) ) {
+ return false;
+ }
+ # Don't make an image bigger than wgMaxSVGSize on the smaller side
+ if ( $params['physicalWidth'] <= $params['physicalHeight'] ) {
+ if ( $params['physicalWidth'] > $wgSVGMaxSize ) {
+ $srcWidth = $image->getWidth( $params['page'] );
+ $srcHeight = $image->getHeight( $params['page'] );
+ $params['physicalWidth'] = $wgSVGMaxSize;
+ $params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight, $wgSVGMaxSize );
+ }
+ } else {
+ if ( $params['physicalHeight'] > $wgSVGMaxSize ) {
+ $srcWidth = $image->getWidth( $params['page'] );
+ $srcHeight = $image->getHeight( $params['page'] );
+ $params['physicalWidth'] = File::scaleHeight( $srcHeight, $srcWidth, $wgSVGMaxSize );
+ $params['physicalHeight'] = $wgSVGMaxSize;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @param File $image
+ * @param string $dstPath
+ * @param string $dstUrl
+ * @param array $params
+ * @param int $flags
+ * @return bool|MediaTransformError|ThumbnailImage|TransformParameterError
+ */
+ function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
+ if ( !$this->normaliseParams( $image, $params ) ) {
+ return new TransformParameterError( $params );
+ }
+ $clientWidth = $params['width'];
+ $clientHeight = $params['height'];
+ $physicalWidth = $params['physicalWidth'];
+ $physicalHeight = $params['physicalHeight'];
+ $lang = isset( $params['lang'] ) ? $params['lang'] : $this->getDefaultRenderLanguage( $image );
+
+ if ( $flags & self::TRANSFORM_LATER ) {
+ return new ThumbnailImage( $image, $dstUrl, $dstPath, $params );
+ }
+
+ $metadata = $this->unpackMetadata( $image->getMetadata() );
+ if ( isset( $metadata['error'] ) ) { // sanity check
+ $err = wfMessage( 'svg-long-error', $metadata['error']['message'] );
+
+ return new MediaTransformError( 'thumbnail_error', $clientWidth, $clientHeight, $err );
+ }
+
+ if ( !wfMkdirParents( dirname( $dstPath ), null, __METHOD__ ) ) {
+ return new MediaTransformError( 'thumbnail_error', $clientWidth, $clientHeight,
+ wfMessage( 'thumbnail_dest_directory' ) );
+ }
+
+ $srcPath = $image->getLocalRefPath();
+ if ( $srcPath === false ) { // Failed to get local copy
+ wfDebugLog( 'thumbnail',
+ sprintf( 'Thumbnail failed on %s: could not get local copy of "%s"',
+ wfHostname(), $image->getName() ) );
+
+ return new MediaTransformError( 'thumbnail_error',
+ $params['width'], $params['height'],
+ wfMessage( 'filemissing' )
+ );
+ }
+
+ // Make a temp dir with a symlink to the local copy in it.
+ // This plays well with rsvg-convert policy for external entities.
+ // https://git.gnome.org/browse/librsvg/commit/?id=f01aded72c38f0e18bc7ff67dee800e380251c8e
+ $tmpDir = wfTempDir() . '/svg_' . wfRandomString( 24 );
+ $lnPath = "$tmpDir/" . basename( $srcPath );
+ $ok = mkdir( $tmpDir, 0771 );
+ if ( !$ok ) {
+ wfDebugLog( 'thumbnail',
+ sprintf( 'Thumbnail failed on %s: could not create temporary directory %s',
+ wfHostname(), $tmpDir ) );
+ return new MediaTransformError( 'thumbnail_error',
+ $params['width'], $params['height'],
+ wfMessage( 'thumbnail-temp-create' )->text()
+ );
+ }
+ $ok = symlink( $srcPath, $lnPath );
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $cleaner = new ScopedCallback( function () use ( $tmpDir, $lnPath ) {
+ Wikimedia\suppressWarnings();
+ unlink( $lnPath );
+ rmdir( $tmpDir );
+ Wikimedia\restoreWarnings();
+ } );
+ if ( !$ok ) {
+ wfDebugLog( 'thumbnail',
+ sprintf( 'Thumbnail failed on %s: could not link %s to %s',
+ wfHostname(), $lnPath, $srcPath ) );
+ return new MediaTransformError( 'thumbnail_error',
+ $params['width'], $params['height'],
+ wfMessage( 'thumbnail-temp-create' )
+ );
+ }
+
+ $status = $this->rasterize( $lnPath, $dstPath, $physicalWidth, $physicalHeight, $lang );
+ if ( $status === true ) {
+ return new ThumbnailImage( $image, $dstUrl, $dstPath, $params );
+ } else {
+ return $status; // MediaTransformError
+ }
+ }
+
+ /**
+ * Transform an SVG file to PNG
+ * This function can be called outside of thumbnail contexts
+ * @param string $srcPath
+ * @param string $dstPath
+ * @param string $width
+ * @param string $height
+ * @param bool|string $lang Language code of the language to render the SVG in
+ * @throws MWException
+ * @return bool|MediaTransformError
+ */
+ public function rasterize( $srcPath, $dstPath, $width, $height, $lang = false ) {
+ global $wgSVGConverters, $wgSVGConverter, $wgSVGConverterPath;
+ $err = false;
+ $retval = '';
+ if ( isset( $wgSVGConverters[$wgSVGConverter] ) ) {
+ if ( is_array( $wgSVGConverters[$wgSVGConverter] ) ) {
+ // This is a PHP callable
+ $func = $wgSVGConverters[$wgSVGConverter][0];
+ $args = array_merge( [ $srcPath, $dstPath, $width, $height, $lang ],
+ array_slice( $wgSVGConverters[$wgSVGConverter], 1 ) );
+ if ( !is_callable( $func ) ) {
+ throw new MWException( "$func is not callable" );
+ }
+ $err = call_user_func_array( $func, $args );
+ $retval = (bool)$err;
+ } else {
+ // External command
+ $cmd = str_replace(
+ [ '$path/', '$width', '$height', '$input', '$output' ],
+ [ $wgSVGConverterPath ? wfEscapeShellArg( "$wgSVGConverterPath/" ) : "",
+ intval( $width ),
+ intval( $height ),
+ wfEscapeShellArg( $srcPath ),
+ wfEscapeShellArg( $dstPath ) ],
+ $wgSVGConverters[$wgSVGConverter]
+ );
+
+ $env = [];
+ if ( $lang !== false ) {
+ $env['LANG'] = $lang;
+ }
+
+ wfDebug( __METHOD__ . ": $cmd\n" );
+ $err = wfShellExecWithStderr( $cmd, $retval, $env );
+ }
+ }
+ $removed = $this->removeBadFile( $dstPath, $retval );
+ if ( $retval != 0 || $removed ) {
+ $this->logErrorForExternalProcess( $retval, $err, $cmd );
+ return new MediaTransformError( 'thumbnail_error', $width, $height, $err );
+ }
+
+ return true;
+ }
+
+ public static function rasterizeImagickExt( $srcPath, $dstPath, $width, $height ) {
+ $im = new Imagick( $srcPath );
+ $im->setImageFormat( 'png' );
+ $im->setBackgroundColor( 'transparent' );
+ $im->setImageDepth( 8 );
+
+ if ( !$im->thumbnailImage( intval( $width ), intval( $height ), /* fit */ false ) ) {
+ return 'Could not resize image';
+ }
+ if ( !$im->writeImage( $dstPath ) ) {
+ return "Could not write to $dstPath";
+ }
+ }
+
+ /**
+ * @param File|FSFile $file
+ * @param string $path Unused
+ * @param bool|array $metadata
+ * @return array
+ */
+ function getImageSize( $file, $path, $metadata = false ) {
+ if ( $metadata === false && $file instanceof File ) {
+ $metadata = $file->getMetadata();
+ }
+ $metadata = $this->unpackMetadata( $metadata );
+
+ if ( isset( $metadata['width'] ) && isset( $metadata['height'] ) ) {
+ return [ $metadata['width'], $metadata['height'], 'SVG',
+ "width=\"{$metadata['width']}\" height=\"{$metadata['height']}\"" ];
+ } else { // error
+ return [ 0, 0, 'SVG', "width=\"0\" height=\"0\"" ];
+ }
+ }
+
+ function getThumbType( $ext, $mime, $params = null ) {
+ return [ 'png', 'image/png' ];
+ }
+
+ /**
+ * Subtitle for the image. Different from the base
+ * class so it can be denoted that SVG's have
+ * a "nominal" resolution, and not a fixed one,
+ * as well as so animation can be denoted.
+ *
+ * @param File $file
+ * @return string
+ */
+ function getLongDesc( $file ) {
+ global $wgLang;
+
+ $metadata = $this->unpackMetadata( $file->getMetadata() );
+ if ( isset( $metadata['error'] ) ) {
+ return wfMessage( 'svg-long-error', $metadata['error']['message'] )->text();
+ }
+
+ $size = $wgLang->formatSize( $file->getSize() );
+
+ if ( $this->isAnimatedImage( $file ) ) {
+ $msg = wfMessage( 'svg-long-desc-animated' );
+ } else {
+ $msg = wfMessage( 'svg-long-desc' );
+ }
+
+ $msg->numParams( $file->getWidth(), $file->getHeight() )->params( $size );
+
+ return $msg->parse();
+ }
+
+ /**
+ * @param File|FSFile $file
+ * @param string $filename
+ * @return string Serialised metadata
+ */
+ function getMetadata( $file, $filename ) {
+ $metadata = [ 'version' => self::SVG_METADATA_VERSION ];
+ try {
+ $metadata += SVGMetadataExtractor::getMetadata( $filename );
+ } catch ( Exception $e ) { // @todo SVG specific exceptions
+ // File not found, broken, etc.
+ $metadata['error'] = [
+ 'message' => $e->getMessage(),
+ 'code' => $e->getCode()
+ ];
+ wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
+ }
+
+ return serialize( $metadata );
+ }
+
+ function unpackMetadata( $metadata ) {
+ Wikimedia\suppressWarnings();
+ $unser = unserialize( $metadata );
+ Wikimedia\restoreWarnings();
+ if ( isset( $unser['version'] ) && $unser['version'] == self::SVG_METADATA_VERSION ) {
+ return $unser;
+ } else {
+ return false;
+ }
+ }
+
+ function getMetadataType( $image ) {
+ return 'parsed-svg';
+ }
+
+ function isMetadataValid( $image, $metadata ) {
+ $meta = $this->unpackMetadata( $metadata );
+ if ( $meta === false ) {
+ return self::METADATA_BAD;
+ }
+ if ( !isset( $meta['originalWidth'] ) ) {
+ // Old but compatible
+ return self::METADATA_COMPATIBLE;
+ }
+
+ return self::METADATA_GOOD;
+ }
+
+ protected function visibleMetadataFields() {
+ $fields = [ 'objectname', 'imagedescription' ];
+
+ return $fields;
+ }
+
+ /**
+ * @param File $file
+ * @param bool|IContextSource $context Context to use (optional)
+ * @return array|bool
+ */
+ function formatMetadata( $file, $context = false ) {
+ $result = [
+ 'visible' => [],
+ 'collapsed' => []
+ ];
+ $metadata = $file->getMetadata();
+ if ( !$metadata ) {
+ return false;
+ }
+ $metadata = $this->unpackMetadata( $metadata );
+ if ( !$metadata || isset( $metadata['error'] ) ) {
+ return false;
+ }
+
+ /* @todo Add a formatter
+ $format = new FormatSVG( $metadata );
+ $formatted = $format->getFormattedData();
+ */
+
+ // Sort fields into visible and collapsed
+ $visibleFields = $this->visibleMetadataFields();
+
+ $showMeta = false;
+ foreach ( $metadata as $name => $value ) {
+ $tag = strtolower( $name );
+ if ( isset( self::$metaConversion[$tag] ) ) {
+ $tag = strtolower( self::$metaConversion[$tag] );
+ } else {
+ // Do not output other metadata not in list
+ continue;
+ }
+ $showMeta = true;
+ self::addMeta( $result,
+ in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed',
+ 'exif',
+ $tag,
+ $value
+ );
+ }
+
+ return $showMeta ? $result : false;
+ }
+
+ /**
+ * @param string $name Parameter name
+ * @param mixed $value Parameter value
+ * @return bool Validity
+ */
+ public function validateParam( $name, $value ) {
+ if ( in_array( $name, [ 'width', 'height' ] ) ) {
+ // Reject negative heights, widths
+ return ( $value > 0 );
+ } elseif ( $name == 'lang' ) {
+ // Validate $code
+ if ( $value === '' || !Language::isValidCode( $value ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ // Only lang, width and height are acceptable keys
+ return false;
+ }
+
+ /**
+ * @param array $params Name=>value pairs of parameters
+ * @return string Filename to use
+ */
+ public function makeParamString( $params ) {
+ $lang = '';
+ if ( isset( $params['lang'] ) && $params['lang'] !== 'en' ) {
+ $lang = 'lang' . strtolower( $params['lang'] ) . '-';
+ }
+ if ( !isset( $params['width'] ) ) {
+ return false;
+ }
+
+ return "$lang{$params['width']}px";
+ }
+
+ public function parseParamString( $str ) {
+ $m = false;
+ if ( preg_match( '/^lang([a-z]+(?:-[a-z]+)*)-(\d+)px$/i', $str, $m ) ) {
+ return [ 'width' => array_pop( $m ), 'lang' => $m[1] ];
+ } elseif ( preg_match( '/^(\d+)px$/', $str, $m ) ) {
+ return [ 'width' => $m[1], 'lang' => 'en' ];
+ } else {
+ return false;
+ }
+ }
+
+ public function getParamMap() {
+ return [ 'img_lang' => 'lang', 'img_width' => 'width' ];
+ }
+
+ /**
+ * @param array $params
+ * @return array
+ */
+ function getScriptParams( $params ) {
+ $scriptParams = [ 'width' => $params['width'] ];
+ if ( isset( $params['lang'] ) ) {
+ $scriptParams['lang'] = $params['lang'];
+ }
+
+ return $scriptParams;
+ }
+
+ public function getCommonMetaArray( File $file ) {
+ $metadata = $file->getMetadata();
+ if ( !$metadata ) {
+ return [];
+ }
+ $metadata = $this->unpackMetadata( $metadata );
+ if ( !$metadata || isset( $metadata['error'] ) ) {
+ return [];
+ }
+ $stdMetadata = [];
+ foreach ( $metadata as $name => $value ) {
+ $tag = strtolower( $name );
+ if ( $tag === 'originalwidth' || $tag === 'originalheight' ) {
+ // Skip these. In the exif metadata stuff, it is assumed these
+ // are measured in px, which is not the case here.
+ continue;
+ }
+ if ( isset( self::$metaConversion[$tag] ) ) {
+ $tag = self::$metaConversion[$tag];
+ $stdMetadata[$tag] = $value;
+ }
+ }
+
+ return $stdMetadata;
+ }
+}
+++ /dev/null
-<?php
-/**
- * Handler for Tiff images.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-/**
- * Handler for Tiff images.
- *
- * @ingroup Media
- */
-class TiffHandler extends ExifBitmapHandler {
- const EXPENSIVE_SIZE_LIMIT = 10485760; // TIFF files over 10M are considered expensive to thumbnail
-
- /**
- * Conversion to PNG for inline display can be disabled here...
- * Note scaling should work with ImageMagick, but may not with GD scaling.
- *
- * Files pulled from an another MediaWiki instance via ForeignAPIRepo /
- * InstantCommons will have thumbnails managed from the remote instance,
- * so we can skip this check.
- *
- * @param File $file
- * @return bool
- */
- public function canRender( $file ) {
- global $wgTiffThumbnailType;
-
- return (bool)$wgTiffThumbnailType
- || $file->getRepo() instanceof ForeignAPIRepo;
- }
-
- /**
- * Browsers don't support TIFF inline generally...
- * For inline display, we need to convert to PNG.
- *
- * @param File $file
- * @return bool
- */
- public function mustRender( $file ) {
- return true;
- }
-
- /**
- * @param string $ext
- * @param string $mime
- * @param array $params
- * @return bool
- */
- function getThumbType( $ext, $mime, $params = null ) {
- global $wgTiffThumbnailType;
-
- return $wgTiffThumbnailType;
- }
-
- /**
- * @param File|FSFile $image
- * @param string $filename
- * @throws MWException
- * @return string
- */
- function getMetadata( $image, $filename ) {
- global $wgShowEXIF;
-
- if ( $wgShowEXIF ) {
- try {
- $meta = BitmapMetadataHandler::Tiff( $filename );
- if ( !is_array( $meta ) ) {
- // This should never happen, but doesn't hurt to be paranoid.
- throw new MWException( 'Metadata array is not an array' );
- }
- $meta['MEDIAWIKI_EXIF_VERSION'] = Exif::version();
-
- return serialize( $meta );
- } catch ( Exception $e ) {
- // BitmapMetadataHandler throws an exception in certain exceptional
- // cases like if file does not exist.
- wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
-
- return ExifBitmapHandler::BROKEN_FILE;
- }
- } else {
- return '';
- }
- }
-
- public function isExpensiveToThumbnail( $file ) {
- return $file->getSize() > static::EXPENSIVE_SIZE_LIMIT;
- }
-}
--- /dev/null
+<?php
+/**
+ * Handler for Tiff images.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * Handler for Tiff images.
+ *
+ * @ingroup Media
+ */
+class TiffHandler extends ExifBitmapHandler {
+ const EXPENSIVE_SIZE_LIMIT = 10485760; // TIFF files over 10M are considered expensive to thumbnail
+
+ /**
+ * Conversion to PNG for inline display can be disabled here...
+ * Note scaling should work with ImageMagick, but may not with GD scaling.
+ *
+ * Files pulled from an another MediaWiki instance via ForeignAPIRepo /
+ * InstantCommons will have thumbnails managed from the remote instance,
+ * so we can skip this check.
+ *
+ * @param File $file
+ * @return bool
+ */
+ public function canRender( $file ) {
+ global $wgTiffThumbnailType;
+
+ return (bool)$wgTiffThumbnailType
+ || $file->getRepo() instanceof ForeignAPIRepo;
+ }
+
+ /**
+ * Browsers don't support TIFF inline generally...
+ * For inline display, we need to convert to PNG.
+ *
+ * @param File $file
+ * @return bool
+ */
+ public function mustRender( $file ) {
+ return true;
+ }
+
+ /**
+ * @param string $ext
+ * @param string $mime
+ * @param array $params
+ * @return bool
+ */
+ function getThumbType( $ext, $mime, $params = null ) {
+ global $wgTiffThumbnailType;
+
+ return $wgTiffThumbnailType;
+ }
+
+ /**
+ * @param File|FSFile $image
+ * @param string $filename
+ * @throws MWException
+ * @return string
+ */
+ function getMetadata( $image, $filename ) {
+ global $wgShowEXIF;
+
+ if ( $wgShowEXIF ) {
+ try {
+ $meta = BitmapMetadataHandler::Tiff( $filename );
+ if ( !is_array( $meta ) ) {
+ // This should never happen, but doesn't hurt to be paranoid.
+ throw new MWException( 'Metadata array is not an array' );
+ }
+ $meta['MEDIAWIKI_EXIF_VERSION'] = Exif::version();
+
+ return serialize( $meta );
+ } catch ( Exception $e ) {
+ // BitmapMetadataHandler throws an exception in certain exceptional
+ // cases like if file does not exist.
+ wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" );
+
+ return ExifBitmapHandler::BROKEN_FILE;
+ }
+ } else {
+ return '';
+ }
+ }
+
+ public function isExpensiveToThumbnail( $file ) {
+ return $file->getSize() > static::EXPENSIVE_SIZE_LIMIT;
+ }
+}
+++ /dev/null
-<?php
-/**
- * Handler for Google's WebP format <https://developers.google.com/speed/webp/>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-/**
- * Handler for Google's WebP format <https://developers.google.com/speed/webp/>
- *
- * @ingroup Media
- */
-class WebPHandler extends BitmapHandler {
- const BROKEN_FILE = '0'; // value to store in img_metadata if error extracting metadata.
- /**
- * @var int Minimum chunk header size to be able to read all header types
- */
- const MINIMUM_CHUNK_HEADER_LENGTH = 18;
- /**
- * @var int version of the metadata stored in db records
- */
- const _MW_WEBP_VERSION = 1;
-
- const VP8X_ICC = 32;
- const VP8X_ALPHA = 16;
- const VP8X_EXIF = 8;
- const VP8X_XMP = 4;
- const VP8X_ANIM = 2;
-
- public function getMetadata( $image, $filename ) {
- $parsedWebPData = self::extractMetadata( $filename );
- if ( !$parsedWebPData ) {
- return self::BROKEN_FILE;
- }
-
- $parsedWebPData['metadata']['_MW_WEBP_VERSION'] = self::_MW_WEBP_VERSION;
- return serialize( $parsedWebPData );
- }
-
- public function getMetadataType( $image ) {
- return 'parsed-webp';
- }
-
- public function isMetadataValid( $image, $metadata ) {
- if ( $metadata === self::BROKEN_FILE ) {
- // Do not repetitivly regenerate metadata on broken file.
- return self::METADATA_GOOD;
- }
-
- Wikimedia\suppressWarnings();
- $data = unserialize( $metadata );
- Wikimedia\restoreWarnings();
-
- if ( !$data || !is_array( $data ) ) {
- wfDebug( __METHOD__ . " invalid WebP metadata\n" );
-
- return self::METADATA_BAD;
- }
-
- if ( !isset( $data['metadata']['_MW_WEBP_VERSION'] )
- || $data['metadata']['_MW_WEBP_VERSION'] != self::_MW_WEBP_VERSION
- ) {
- wfDebug( __METHOD__ . " old but compatible WebP metadata\n" );
-
- return self::METADATA_COMPATIBLE;
- }
- return self::METADATA_GOOD;
- }
-
- /**
- * Extracts the image size and WebP type from a file
- *
- * @param string $filename
- * @return array|bool Header data array with entries 'compression', 'width' and 'height',
- * where 'compression' can be 'lossy', 'lossless', 'animated' or 'unknown'. False if
- * file is not a valid WebP file.
- */
- public static function extractMetadata( $filename ) {
- wfDebugLog( 'WebP', __METHOD__ . ": Extracting metadata from $filename\n" );
-
- $info = RiffExtractor::findChunksFromFile( $filename, 100 );
- if ( $info === false ) {
- wfDebugLog( 'WebP', __METHOD__ . ": Not a valid RIFF file\n" );
- return false;
- }
-
- if ( $info['fourCC'] != 'WEBP' ) {
- wfDebugLog( 'WebP', __METHOD__ . ': FourCC was not WEBP: ' .
- bin2hex( $info['fourCC'] ) . " \n" );
- return false;
- }
-
- $metadata = self::extractMetadataFromChunks( $info['chunks'], $filename );
- if ( !$metadata ) {
- wfDebugLog( 'WebP', __METHOD__ . ": No VP8 chunks found\n" );
- return false;
- }
-
- return $metadata;
- }
-
- /**
- * Extracts the image size and WebP type from a file based on the chunk list
- * @param array $chunks Chunks as extracted by RiffExtractor
- * @param string $filename
- * @return array Header data array with entries 'compression', 'width' and 'height', where
- * 'compression' can be 'lossy', 'lossless', 'animated' or 'unknown'
- */
- public static function extractMetadataFromChunks( $chunks, $filename ) {
- $vp8Info = [];
-
- foreach ( $chunks as $chunk ) {
- if ( !in_array( $chunk['fourCC'], [ 'VP8 ', 'VP8L', 'VP8X' ] ) ) {
- // Not a chunk containing interesting metadata
- continue;
- }
-
- $chunkHeader = file_get_contents( $filename, false, null,
- $chunk['start'], self::MINIMUM_CHUNK_HEADER_LENGTH );
- wfDebugLog( 'WebP', __METHOD__ . ": {$chunk['fourCC']}\n" );
-
- switch ( $chunk['fourCC'] ) {
- case 'VP8 ':
- return array_merge( $vp8Info,
- self::decodeLossyChunkHeader( $chunkHeader ) );
- case 'VP8L':
- return array_merge( $vp8Info,
- self::decodeLosslessChunkHeader( $chunkHeader ) );
- case 'VP8X':
- $vp8Info = array_merge( $vp8Info,
- self::decodeExtendedChunkHeader( $chunkHeader ) );
- // Continue looking for other chunks to improve the metadata
- break;
- }
- }
- return $vp8Info;
- }
-
- /**
- * Decodes a lossy chunk header
- * @param string $header First few bytes of the header, expected to be at least 18 bytes long
- * @return bool|array See WebPHandler::decodeHeader
- */
- protected static function decodeLossyChunkHeader( $header ) {
- // Bytes 0-3 are 'VP8 '
- // Bytes 4-7 are the VP8 stream size
- // Bytes 8-10 are the frame tag
- // Bytes 11-13 are 0x9D 0x01 0x2A called the sync code
- $syncCode = substr( $header, 11, 3 );
- if ( $syncCode != "\x9D\x01\x2A" ) {
- wfDebugLog( 'WebP', __METHOD__ . ': Invalid sync code: ' .
- bin2hex( $syncCode ) . "\n" );
- return [];
- }
- // Bytes 14-17 are image size
- $imageSize = unpack( 'v2', substr( $header, 14, 4 ) );
- // Image sizes are 14 bit, 2 MSB are scaling parameters which are ignored here
- return [
- 'compression' => 'lossy',
- 'width' => $imageSize[1] & 0x3FFF,
- 'height' => $imageSize[2] & 0x3FFF
- ];
- }
-
- /**
- * Decodes a lossless chunk header
- * @param string $header First few bytes of the header, expected to be at least 13 bytes long
- * @return bool|array See WebPHandler::decodeHeader
- */
- public static function decodeLosslessChunkHeader( $header ) {
- // Bytes 0-3 are 'VP8L'
- // Bytes 4-7 are chunk stream size
- // Byte 8 is 0x2F called the signature
- if ( $header{8} != "\x2F" ) {
- wfDebugLog( 'WebP', __METHOD__ . ': Invalid signature: ' .
- bin2hex( $header{8} ) . "\n" );
- return [];
- }
- // Bytes 9-12 contain the image size
- // Bits 0-13 are width-1; bits 15-27 are height-1
- $imageSize = unpack( 'C4', substr( $header, 9, 4 ) );
- return [
- 'compression' => 'lossless',
- 'width' => ( $imageSize[1] | ( ( $imageSize[2] & 0x3F ) << 8 ) ) + 1,
- 'height' => ( ( ( $imageSize[2] & 0xC0 ) >> 6 ) |
- ( $imageSize[3] << 2 ) | ( ( $imageSize[4] & 0x03 ) << 10 ) ) + 1
- ];
- }
-
- /**
- * Decodes an extended chunk header
- * @param string $header First few bytes of the header, expected to be at least 18 bytes long
- * @return bool|array See WebPHandler::decodeHeader
- */
- public static function decodeExtendedChunkHeader( $header ) {
- // Bytes 0-3 are 'VP8X'
- // Byte 4-7 are chunk length
- // Byte 8-11 are a flag bytes
- $flags = unpack( 'c', substr( $header, 8, 1 ) );
-
- // Byte 12-17 are image size (24 bits)
- $width = unpack( 'V', substr( $header, 12, 3 ) . "\x00" );
- $height = unpack( 'V', substr( $header, 15, 3 ) . "\x00" );
-
- return [
- 'compression' => 'unknown',
- 'animated' => ( $flags[1] & self::VP8X_ANIM ) == self::VP8X_ANIM,
- 'transparency' => ( $flags[1] & self::VP8X_ALPHA ) == self::VP8X_ALPHA,
- 'width' => ( $width[1] & 0xFFFFFF ) + 1,
- 'height' => ( $height[1] & 0xFFFFFF ) + 1
- ];
- }
-
- public function getImageSize( $file, $path, $metadata = false ) {
- if ( $file === null ) {
- $metadata = self::getMetadata( $file, $path );
- }
- if ( $metadata === false && $file instanceof File ) {
- $metadata = $file->getMetadata();
- }
-
- Wikimedia\suppressWarnings();
- $metadata = unserialize( $metadata );
- Wikimedia\restoreWarnings();
-
- if ( $metadata == false ) {
- return false;
- }
- return [ $metadata['width'], $metadata['height'] ];
- }
-
- /**
- * @param File $file
- * @return bool True, not all browsers support WebP
- */
- public function mustRender( $file ) {
- return true;
- }
-
- /**
- * @param File $file
- * @return bool False if we are unable to render this image
- */
- public function canRender( $file ) {
- if ( self::isAnimatedImage( $file ) ) {
- return false;
- }
- return true;
- }
-
- /**
- * @param File $image
- * @return bool
- */
- public function isAnimatedImage( $image ) {
- $ser = $image->getMetadata();
- if ( $ser ) {
- $metadata = unserialize( $ser );
- if ( isset( $metadata['animated'] ) && $metadata['animated'] === true ) {
- return true;
- }
- }
-
- return false;
- }
-
- public function canAnimateThumbnail( $file ) {
- return false;
- }
-
- /**
- * Render files as PNG
- *
- * @param string $ext
- * @param string $mime
- * @param array|null $params
- * @return array
- */
- public function getThumbType( $ext, $mime, $params = null ) {
- return [ 'png', 'image/png' ];
- }
-
- /**
- * Must use "im" for XCF
- *
- * @param string $dstPath
- * @param bool $checkDstPath
- * @return string
- */
- protected function getScalerType( $dstPath, $checkDstPath = true ) {
- return 'im';
- }
-}
--- /dev/null
+<?php
+/**
+ * Handler for Google's WebP format <https://developers.google.com/speed/webp/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * Handler for Google's WebP format <https://developers.google.com/speed/webp/>
+ *
+ * @ingroup Media
+ */
+class WebPHandler extends BitmapHandler {
+ const BROKEN_FILE = '0'; // value to store in img_metadata if error extracting metadata.
+ /**
+ * @var int Minimum chunk header size to be able to read all header types
+ */
+ const MINIMUM_CHUNK_HEADER_LENGTH = 18;
+ /**
+ * @var int version of the metadata stored in db records
+ */
+ const _MW_WEBP_VERSION = 1;
+
+ const VP8X_ICC = 32;
+ const VP8X_ALPHA = 16;
+ const VP8X_EXIF = 8;
+ const VP8X_XMP = 4;
+ const VP8X_ANIM = 2;
+
+ public function getMetadata( $image, $filename ) {
+ $parsedWebPData = self::extractMetadata( $filename );
+ if ( !$parsedWebPData ) {
+ return self::BROKEN_FILE;
+ }
+
+ $parsedWebPData['metadata']['_MW_WEBP_VERSION'] = self::_MW_WEBP_VERSION;
+ return serialize( $parsedWebPData );
+ }
+
+ public function getMetadataType( $image ) {
+ return 'parsed-webp';
+ }
+
+ public function isMetadataValid( $image, $metadata ) {
+ if ( $metadata === self::BROKEN_FILE ) {
+ // Do not repetitivly regenerate metadata on broken file.
+ return self::METADATA_GOOD;
+ }
+
+ Wikimedia\suppressWarnings();
+ $data = unserialize( $metadata );
+ Wikimedia\restoreWarnings();
+
+ if ( !$data || !is_array( $data ) ) {
+ wfDebug( __METHOD__ . " invalid WebP metadata\n" );
+
+ return self::METADATA_BAD;
+ }
+
+ if ( !isset( $data['metadata']['_MW_WEBP_VERSION'] )
+ || $data['metadata']['_MW_WEBP_VERSION'] != self::_MW_WEBP_VERSION
+ ) {
+ wfDebug( __METHOD__ . " old but compatible WebP metadata\n" );
+
+ return self::METADATA_COMPATIBLE;
+ }
+ return self::METADATA_GOOD;
+ }
+
+ /**
+ * Extracts the image size and WebP type from a file
+ *
+ * @param string $filename
+ * @return array|bool Header data array with entries 'compression', 'width' and 'height',
+ * where 'compression' can be 'lossy', 'lossless', 'animated' or 'unknown'. False if
+ * file is not a valid WebP file.
+ */
+ public static function extractMetadata( $filename ) {
+ wfDebugLog( 'WebP', __METHOD__ . ": Extracting metadata from $filename\n" );
+
+ $info = RiffExtractor::findChunksFromFile( $filename, 100 );
+ if ( $info === false ) {
+ wfDebugLog( 'WebP', __METHOD__ . ": Not a valid RIFF file\n" );
+ return false;
+ }
+
+ if ( $info['fourCC'] != 'WEBP' ) {
+ wfDebugLog( 'WebP', __METHOD__ . ': FourCC was not WEBP: ' .
+ bin2hex( $info['fourCC'] ) . " \n" );
+ return false;
+ }
+
+ $metadata = self::extractMetadataFromChunks( $info['chunks'], $filename );
+ if ( !$metadata ) {
+ wfDebugLog( 'WebP', __METHOD__ . ": No VP8 chunks found\n" );
+ return false;
+ }
+
+ return $metadata;
+ }
+
+ /**
+ * Extracts the image size and WebP type from a file based on the chunk list
+ * @param array $chunks Chunks as extracted by RiffExtractor
+ * @param string $filename
+ * @return array Header data array with entries 'compression', 'width' and 'height', where
+ * 'compression' can be 'lossy', 'lossless', 'animated' or 'unknown'
+ */
+ public static function extractMetadataFromChunks( $chunks, $filename ) {
+ $vp8Info = [];
+
+ foreach ( $chunks as $chunk ) {
+ if ( !in_array( $chunk['fourCC'], [ 'VP8 ', 'VP8L', 'VP8X' ] ) ) {
+ // Not a chunk containing interesting metadata
+ continue;
+ }
+
+ $chunkHeader = file_get_contents( $filename, false, null,
+ $chunk['start'], self::MINIMUM_CHUNK_HEADER_LENGTH );
+ wfDebugLog( 'WebP', __METHOD__ . ": {$chunk['fourCC']}\n" );
+
+ switch ( $chunk['fourCC'] ) {
+ case 'VP8 ':
+ return array_merge( $vp8Info,
+ self::decodeLossyChunkHeader( $chunkHeader ) );
+ case 'VP8L':
+ return array_merge( $vp8Info,
+ self::decodeLosslessChunkHeader( $chunkHeader ) );
+ case 'VP8X':
+ $vp8Info = array_merge( $vp8Info,
+ self::decodeExtendedChunkHeader( $chunkHeader ) );
+ // Continue looking for other chunks to improve the metadata
+ break;
+ }
+ }
+ return $vp8Info;
+ }
+
+ /**
+ * Decodes a lossy chunk header
+ * @param string $header First few bytes of the header, expected to be at least 18 bytes long
+ * @return bool|array See WebPHandler::decodeHeader
+ */
+ protected static function decodeLossyChunkHeader( $header ) {
+ // Bytes 0-3 are 'VP8 '
+ // Bytes 4-7 are the VP8 stream size
+ // Bytes 8-10 are the frame tag
+ // Bytes 11-13 are 0x9D 0x01 0x2A called the sync code
+ $syncCode = substr( $header, 11, 3 );
+ if ( $syncCode != "\x9D\x01\x2A" ) {
+ wfDebugLog( 'WebP', __METHOD__ . ': Invalid sync code: ' .
+ bin2hex( $syncCode ) . "\n" );
+ return [];
+ }
+ // Bytes 14-17 are image size
+ $imageSize = unpack( 'v2', substr( $header, 14, 4 ) );
+ // Image sizes are 14 bit, 2 MSB are scaling parameters which are ignored here
+ return [
+ 'compression' => 'lossy',
+ 'width' => $imageSize[1] & 0x3FFF,
+ 'height' => $imageSize[2] & 0x3FFF
+ ];
+ }
+
+ /**
+ * Decodes a lossless chunk header
+ * @param string $header First few bytes of the header, expected to be at least 13 bytes long
+ * @return bool|array See WebPHandler::decodeHeader
+ */
+ public static function decodeLosslessChunkHeader( $header ) {
+ // Bytes 0-3 are 'VP8L'
+ // Bytes 4-7 are chunk stream size
+ // Byte 8 is 0x2F called the signature
+ if ( $header{8} != "\x2F" ) {
+ wfDebugLog( 'WebP', __METHOD__ . ': Invalid signature: ' .
+ bin2hex( $header{8} ) . "\n" );
+ return [];
+ }
+ // Bytes 9-12 contain the image size
+ // Bits 0-13 are width-1; bits 15-27 are height-1
+ $imageSize = unpack( 'C4', substr( $header, 9, 4 ) );
+ return [
+ 'compression' => 'lossless',
+ 'width' => ( $imageSize[1] | ( ( $imageSize[2] & 0x3F ) << 8 ) ) + 1,
+ 'height' => ( ( ( $imageSize[2] & 0xC0 ) >> 6 ) |
+ ( $imageSize[3] << 2 ) | ( ( $imageSize[4] & 0x03 ) << 10 ) ) + 1
+ ];
+ }
+
+ /**
+ * Decodes an extended chunk header
+ * @param string $header First few bytes of the header, expected to be at least 18 bytes long
+ * @return bool|array See WebPHandler::decodeHeader
+ */
+ public static function decodeExtendedChunkHeader( $header ) {
+ // Bytes 0-3 are 'VP8X'
+ // Byte 4-7 are chunk length
+ // Byte 8-11 are a flag bytes
+ $flags = unpack( 'c', substr( $header, 8, 1 ) );
+
+ // Byte 12-17 are image size (24 bits)
+ $width = unpack( 'V', substr( $header, 12, 3 ) . "\x00" );
+ $height = unpack( 'V', substr( $header, 15, 3 ) . "\x00" );
+
+ return [
+ 'compression' => 'unknown',
+ 'animated' => ( $flags[1] & self::VP8X_ANIM ) == self::VP8X_ANIM,
+ 'transparency' => ( $flags[1] & self::VP8X_ALPHA ) == self::VP8X_ALPHA,
+ 'width' => ( $width[1] & 0xFFFFFF ) + 1,
+ 'height' => ( $height[1] & 0xFFFFFF ) + 1
+ ];
+ }
+
+ public function getImageSize( $file, $path, $metadata = false ) {
+ if ( $file === null ) {
+ $metadata = self::getMetadata( $file, $path );
+ }
+ if ( $metadata === false && $file instanceof File ) {
+ $metadata = $file->getMetadata();
+ }
+
+ Wikimedia\suppressWarnings();
+ $metadata = unserialize( $metadata );
+ Wikimedia\restoreWarnings();
+
+ if ( $metadata == false ) {
+ return false;
+ }
+ return [ $metadata['width'], $metadata['height'] ];
+ }
+
+ /**
+ * @param File $file
+ * @return bool True, not all browsers support WebP
+ */
+ public function mustRender( $file ) {
+ return true;
+ }
+
+ /**
+ * @param File $file
+ * @return bool False if we are unable to render this image
+ */
+ public function canRender( $file ) {
+ if ( self::isAnimatedImage( $file ) ) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param File $image
+ * @return bool
+ */
+ public function isAnimatedImage( $image ) {
+ $ser = $image->getMetadata();
+ if ( $ser ) {
+ $metadata = unserialize( $ser );
+ if ( isset( $metadata['animated'] ) && $metadata['animated'] === true ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function canAnimateThumbnail( $file ) {
+ return false;
+ }
+
+ /**
+ * Render files as PNG
+ *
+ * @param string $ext
+ * @param string $mime
+ * @param array|null $params
+ * @return array
+ */
+ public function getThumbType( $ext, $mime, $params = null ) {
+ return [ 'png', 'image/png' ];
+ }
+
+ /**
+ * Must use "im" for XCF
+ *
+ * @param string $dstPath
+ * @param bool $checkDstPath
+ * @return string
+ */
+ protected function getScalerType( $dstPath, $checkDstPath = true ) {
+ return 'im';
+ }
+}
if ( 0 == $prefixLength ) {
# No prefix (not in list)--go to paragraph mode
# @todo consider using a stack for nestable elements like span, table and div
+
+ // P-wrapping and indent-pre are suppressed inside, not outside
+ $blockElems = 'table|h1|h2|h3|h4|h5|h6|pre|p|ul|ol|dl|li';
+ // P-wrapping and indent-pre are suppressed outside, not inside
+ $antiBlockElems = 'td|th';
+
$openMatch = preg_match(
- '/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|'
- . '<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)\\b/iS',
+ '/<('
+ . "({$blockElems})|\\/({$antiBlockElems})|"
+ // Always suppresses
+ . '\\/?(tr)'
+ . ')\\b/iS',
$t
);
$closeMatch = preg_match(
- '/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'
- . '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|'
- . Parser::MARKER_PREFIX
- . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)\\b/iS',
+ '/<('
+ . "\\/({$blockElems})|({$antiBlockElems})|"
+ // Never suppresses
+ . '\\/?(center|blockquote|div|hr|mw:)'
+ . ')\\b/iS',
$t
);
+ // Any match closes the paragraph, but only when `!$closeMatch`
+ // do we enter block mode. The oddities with table rows and
+ // cells are to avoid paragraph wrapping in interstitial spaces
+ // leading to fostered content.
+
if ( $openMatch || $closeMatch ) {
$pendingPTag = false;
// Only close the paragraph if we're not inside a <pre> tag, or if
}
}
+ /**
+ * @see OutputPage::addModules
+ */
public function addModules( $modules ) {
$this->mModules = array_merge( $this->mModules, (array)$modules );
}
+ /**
+ * @deprecated since 1.31 Use addModules() instead.
+ * @see OutputPage::addModuleScripts
+ */
public function addModuleScripts( $modules ) {
$this->mModuleScripts = array_merge( $this->mModuleScripts, (array)$modules );
}
+ /**
+ * @see OutputPage::addModuleStyles
+ */
public function addModuleStyles( $modules ) {
$this->mModuleStyles = array_merge( $this->mModuleStyles, (array)$modules );
}
} elseif ( $found == 'line-end' ) {
$piece = $stack->top;
// A heading must be open, otherwise \n wouldn't have been in the search list
+ // FIXME: Don't use assert()
+ // phpcs:ignore MediaWiki.Usage.ForbiddenFunctions.assert
assert( $piece->open === "\n" );
$part = $piece->getCurrentPart();
// Search back through the input to see if it has a proper close.
} elseif ( $found == 'line-end' ) {
$piece = $stack->top;
// A heading must be open, otherwise \n wouldn't have been in the search list
+ // FIXME: Don't use assert()
+ // phpcs:ignore MediaWiki.Usage.ForbiddenFunctions.assert
assert( $piece->open === "\n" );
$part = $piece->getCurrentPart();
// Search back through the input to see if it has a proper close.
/**
* Given a value, escape it so that it can be used in an id attribute and
- * return it. This will use HTML5 validation if $wgExperimentalHtmlIds is
- * true, allowing anything but ASCII whitespace. Otherwise it will use
- * HTML 4 rules, which means a narrow subset of ASCII, with bad characters
- * escaped with lots of dots.
+ * return it. This will use HTML5 validation, allowing anything but ASCII
+ * whitespace.
+ *
+ * To ensure we don't have to bother escaping anything, we also strip ', ".
+ * TODO: Is this the best tactic?
*
- * To ensure we don't have to bother escaping anything, we also strip ', ",
- * & even if $wgExperimentalIds is true. TODO: Is this the best tactic?
* We also strip # because it upsets IE, and % because it could be
* ambiguous if it's part of something that looks like a percent escape
* (which don't work reliably in fragments cross-browser).
* @param string|array $options String or array of strings (default is array()):
* 'noninitial': This is a non-initial fragment of an id, not a full id,
* so don't pay attention if the first character isn't valid at the
- * beginning of an id. Only matters if $wgExperimentalHtmlIds is
- * false.
- * 'legacy': Behave the way the old HTML 4-based ID escaping worked even
- * if $wgExperimentalHtmlIds is used, so we can generate extra
- * anchors and links won't break.
+ * beginning of an id.
* @return string
*/
static function escapeId( $id, $options = [] ) {
- global $wgExperimentalHtmlIds;
$options = (array)$options;
- if ( $wgExperimentalHtmlIds && !in_array( 'legacy', $options ) ) {
- $id = preg_replace( '/[ \t\n\r\f_\'"&#%]+/', '_', $id );
- $id = trim( $id, '_' );
- if ( $id === '' ) {
- // Must have been all whitespace to start with.
- return '_';
- } else {
- return $id;
- }
- }
-
// HTML4-style escaping
static $replace = [
'%3A' => ':',
$id = urlencode( str_replace( ' ', '_', $id ) );
$id = strtr( $id, $replace );
break;
- case 'html5-legacy':
- $id = preg_replace( '/[ \t\n\r\f_\'"&#%]+/', '_', $id );
- $id = trim( $id, '_' );
- if ( $id === '' ) {
- // Must have been all whitespace to start with.
- $id = '_';
- }
- break;
default:
throw new InvalidArgumentException( "Invalid mode '$mode' passed to '" . __METHOD__ );
}
}
/**
+ * Non-static proxy to ::getLogo (for overloading in sub classes or tests).
+ *
+ * @codeCoverageIgnore
* @since 1.31
* @param Config $conf
* @return string|array
public function getDefaultModules() {
$out = $this->getOutput();
$config = $this->getConfig();
- $user = $out->getUser();
+ $user = $this->getUser();
+
+ // Modules declared in the $modules literal are loaded
+ // for ALL users, on ALL pages, in ALL skins.
+ // Keep this list as small as possible!
$modules = [
- // Styles key sets render blocking styles
- // Unlike other keys in this definition it is an associative array
- // where each key is the group name and points to a list of modules
- 'styles' => [],
- // modules not specific to any specific skin or page
+ 'styles' => [
+ // The 'styles' key sets render-blocking style modules
+ // Unlike other keys in $modules, this is an associative array
+ // where each key is its own group pointing to a list of modules
+ 'core' => [
+ 'mediawiki.legacy.shared',
+ 'mediawiki.legacy.commonPrint',
+ ],
+ 'content' => [],
+ 'syndicate' => [],
+ ],
'core' => [
- // Enforce various default modules for all pages and all skins
- // Keep this list as small as possible
'site',
'mediawiki.page.startup',
'mediawiki.user',
],
- // modules that enhance the page content in some way
+ // modules that enhance the content in some way
'content' => [
'mediawiki.page.ready',
],
'watch' => [],
// modules which relate to the current users preferences
'user' => [],
+ // modules relating to RSS/Atom Feeds
+ 'syndicate' => [],
];
// Support for high-density display images if enabled
// Preload jquery.tablesorter for mediawiki.page.ready
if ( strpos( $out->getHTML(), 'sortable' ) !== false ) {
$modules['content'][] = 'jquery.tablesorter';
+ $modules['styles']['content'][] = 'jquery.tablesorter.styles';
}
// Preload jquery.makeCollapsible for mediawiki.page.ready
if ( strpos( $out->getHTML(), 'mw-collapsible' ) !== false ) {
$modules['content'][] = 'jquery.makeCollapsible';
+ $modules['styles']['content'][] = 'jquery.makeCollapsible.styles';
+ }
+
+ // Deprecated since 1.26: Unconditional loading of mediawiki.ui.button
+ // on every page is deprecated. Express a dependency instead.
+ if ( strpos( $out->getHTML(), 'mw-ui-button' ) !== false ) {
+ $modules['styles']['content'][] = 'mediawiki.ui.button';
}
if ( $out->isTOCEnabled() ) {
if ( $out->isArticle() && $user->getOption( 'editondblclick' ) ) {
$modules['user'][] = 'mediawiki.action.view.dblClickEdit';
}
+
+ if ( $out->isSyndicated() ) {
+ $modules['styles']['syndicate'][] = 'mediawiki.feedlink';
+ }
+
return $modules;
}
}
/**
- * Add skin specific stylesheets
- * Calling this method with an $out of anything but the same OutputPage
- * inside ->getOutput() is deprecated. The $out arg is kept
- * for compatibility purposes with skins.
- * @param OutputPage $out
- * @todo delete
+ * Hook point for adding style modules to OutputPage.
+ *
+ * @deprecated since 1.32 Use getDefaultModules() instead.
+ * @param OutputPage $out Legacy parameter, identical to $this->getOutput()
*/
- abstract function setupSkinUserCss( OutputPage $out );
+ public function setupSkinUserCss( OutputPage $out ) {
+ // Stub.
+ }
/**
* TODO: document
public $username;
public $userpageUrlDetails;
- /**
- * Add specific styles for this skin
- *
- * @param OutputPage $out
- */
- public function setupSkinUserCss( OutputPage $out ) {
- $moduleStyles = [
- 'mediawiki.legacy.shared',
- 'mediawiki.legacy.commonPrint',
- 'mediawiki.sectionAnchor'
- ];
- if ( $out->isSyndicated() ) {
- $moduleStyles[] = 'mediawiki.feedlink';
- }
-
- // Deprecated since 1.26: Unconditional loading of mediawiki.ui.button
- // on every page is deprecated. Express a dependency instead.
- if ( strpos( $out->getHTML(), 'mw-ui-button' ) !== false ) {
- $moduleStyles[] = 'mediawiki.ui.button';
- }
-
- $out->addModuleStyles( $moduleStyles );
- }
-
/**
* Create the template engine object; we feed it a bunch of data
* and eventually it spits out some HTML. Should have interface
protected function buildForm() {
$groups = User::getAllGroups();
+ $options = [];
foreach ( $groups as $group ) {
$msg = htmlspecialchars( UserGroupMembership::getGroupName( $group ) );
$options[$msg] = $group;
}
+ asort( $options );
// Backwards-compatibility with old URLs
$req = $this->getRequest();
];
$context = new DerivativeContext( $this->getContext() );
$context->setTitle( $this->getPageTitle( 'raw' ) ); // Reset subpage
- $form = new HTMLForm( $fields, $context );
+ $form = new OOUIHTMLForm( $fields, $context );
$form->setSubmitTextMsg( 'watchlistedit-raw-submit' );
# Used message keys: 'accesskey-watchlistedit-raw-submit', 'tooltip-watchlistedit-raw-submit'
$form->setSubmitTooltip( 'watchlistedit-raw-submit' );
protected function getClearForm() {
$context = new DerivativeContext( $this->getContext() );
$context->setTitle( $this->getPageTitle( 'clear' ) ); // Reset subpage
- $form = new HTMLForm( [], $context );
+ $form = new OOUIHTMLForm( [], $context );
$form->setSubmitTextMsg( 'watchlistedit-clear-submit' );
# Used message keys: 'accesskey-watchlistedit-clear-submit', 'tooltip-watchlistedit-clear-submit'
$form->setSubmitTooltip( 'watchlistedit-clear-submit' );
$opts->add( 'dir', '' );
$opts->add( 'offender', '' );
$opts->add( 'subtype', '' );
+ $opts->add( 'logid', '' );
// Set values
$opts->fetchValuesFromRequest( $this->getRequest() );
return $subpages;
}
+ /**
+ * Set options based on the subpage title parts:
+ * - One part that is a valid log type: Special:Log/logtype
+ * - Two parts: Special:Log/logtype/username
+ * - Otherwise, assume the whole subpage is a username.
+ *
+ * @param FormOptions $opts
+ * @param $par
+ * @throws ConfigException
+ */
private function parseParams( FormOptions $opts, $par ) {
# Get parameters
$par = $par !== null ? $par : '';
$opts->getValue( 'year' ),
$opts->getValue( 'month' ),
$opts->getValue( 'tagfilter' ),
- $opts->getValue( 'subtype' )
+ $opts->getValue( 'subtype' ),
+ $opts->getValue( 'logid' )
);
$this->addHeader( $opts->getValue( 'type' ) );
public function alterForm( HTMLForm $form ) {
$resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
+ $form->setSubmitDestructive();
+
$form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
$i = 0;
/**
* Handle Special:Redirect/logid/xxx
- * (by redirecting to index.php?title=Special:Log)
+ * (by redirecting to index.php?title=Special:Log&logid=xxx)
*
* @since 1.27
* @return string|null Url to redirect to, or null if $mValue is invalid.
if ( $logid === 0 ) {
return null;
}
-
- $logQuery = ActorMigration::newMigration()->getJoin( 'log_user' );
-
- $logparams = [
- 'log_id' => 'log_id',
- 'log_timestamp' => 'log_timestamp',
- 'log_type' => 'log_type',
- 'log_user_text' => $logQuery['fields']['log_user_text'],
- ];
-
- $dbr = wfGetDB( DB_REPLICA );
-
- // Gets the nested SQL statement which
- // returns timestamp of the log with the given log ID
- $inner = $dbr->selectSQLText(
- 'logging',
- [ 'log_timestamp' ],
- [ 'log_id' => $logid ]
- );
-
- // Returns all fields mentioned in $logparams of the logs
- // with the same timestamp as the one returned by the statement above
- $logsSameTimestamps = $dbr->select(
- [ 'logging' ] + $logQuery['tables'],
- $logparams,
- [ "log_timestamp = ($inner)" ],
- __METHOD__,
- [],
- $logQuery['joins']
- );
- if ( $logsSameTimestamps->numRows() === 0 ) {
- return null;
- }
-
- // Stores the row with the same log ID as the one given
- $rowMain = [];
- foreach ( $logsSameTimestamps as $row ) {
- if ( (int)$row->log_id === $logid ) {
- $rowMain = $row;
- }
- }
-
- array_shift( $logparams );
-
- // Stores all the rows with the same values in each column
- // as $rowMain
- foreach ( $logparams as $key => $dummy ) {
- $matchedRows = [];
- foreach ( $logsSameTimestamps as $row ) {
- if ( $row->$key === $rowMain->$key ) {
- $matchedRows[] = $row;
- }
- }
- if ( count( $matchedRows ) === 1 ) {
- break;
- }
- $logsSameTimestamps = $matchedRows;
- }
- $query = [ 'title' => 'Special:Log', 'limit' => count( $matchedRows ) ];
-
- // A map of database field names from table 'logging' to the values of $logparams
- $keys = [
- 'log_timestamp' => 'offset',
- 'log_type' => 'type',
- 'log_user_text' => 'user'
- ];
-
- foreach ( $logparams as $logKey => $dummy ) {
- $query[$keys[$logKey]] = $matchedRows[0]->$logKey;
- }
- $query['offset'] = $query['offset'] + 1;
- $url = $query;
-
- return wfAppendQuery( wfScript( 'index' ), $url );
+ $query = [ 'title' => 'Special:Log', 'logid' => $logid ];
+ return wfAppendQuery( wfScript( 'index' ), $query );
}
/**
* @param HTMLForm $form
*/
protected function alterForm( HTMLForm $form ) {
+ $form->setSubmitDestructive();
if ( $this->getTokensList() ) {
$form->setSubmitTextMsg( 'resettokens-resetbutton' );
} else {
Xml::closeElement( 'tr' ) .
$this->formatRow( $this->msg( 'statistics-users' )->parse() . ' ' .
$this->getLinkRenderer()->makeKnownLink(
- SpecialPage::getTitleFor( 'ListUsers' ),
+ SpecialPage::getTitleFor( 'Listusers' ),
$this->msg( 'listgrouprights-members' )->text()
),
$this->getLanguage()->formatNum( $this->users ),
$out = $this->getOutput();
$out->setPageTitle( $this->msg( 'unblockip' ) );
+ $out->addModules( [ 'mediawiki.userSuggest' ] );
$form = HTMLForm::factory( 'ooui', $this->getFields(), $this->getContext() );
$form->setWrapperLegendMsg( 'unblockip' );
protected function getFields() {
$fields = [
'Target' => [
- 'type' => 'user',
+ 'type' => 'text',
'label-message' => 'ipaddressorusername',
'autofocus' => true,
'size' => '45',
'required' => true,
+ 'cssclass' => 'mw-autocomplete-user', // used by mediawiki.userSuggest
],
'Name' => [
'type' => 'info',
}
// T171345: Add a hidden form element so that other groups can still be manipulated,
// otherwise saving errors out with an invalid expiry time for this group.
- $expiryHtml .= Html::Hidden( "wpExpiry-$group",
+ $expiryHtml .= Html::hidden( "wpExpiry-$group",
$currentExpiry ? 'existing' : 'infinite' );
$expiryHtml .= "<br />\n";
} else {
*/
/**
- * Extend HTMLForm purely so we can have a more sane way of getting the section headers
+ * Extend OOUIHTMLForm purely so we can have a more sane way of getting the section headers
*/
-class EditWatchlistNormalHTMLForm extends HTMLForm {
+class EditWatchlistNormalHTMLForm extends OOUIHTMLForm {
public function getLegend( $namespace ) {
$namespace = substr( $namespace, 2 );
? $this->msg( 'blanknamespace' )->escaped()
: htmlspecialchars( $this->getContext()->getLanguage()->getFormattedNsText( $namespace ) );
}
-
- public function getBody() {
- return $this->displaySection( $this->mFieldTree, '', 'editwatchlist-' );
- }
}
}
function getForm() {
- $fields = [];
- $fields['limit'] = [
+ $formDescriptor = [];
+ $formDescriptor['limit'] = [
'type' => 'select',
'name' => 'limit',
'label-message' => 'table_pager_limit_label',
];
if ( !$this->getConfig()->get( 'MiserMode' ) ) {
- $fields['ilsearch'] = [
+ $formDescriptor['ilsearch'] = [
'type' => 'text',
'name' => 'ilsearch',
'id' => 'mw-ilsearch',
];
}
- $fields['user'] = [
+ $formDescriptor['user'] = [
'type' => 'user',
'name' => 'user',
'id' => 'mw-listfiles-user',
'maxlength' => '255',
];
- $fields['ilshowall'] = [
+ $formDescriptor['ilshowall'] = [
'type' => 'check',
'name' => 'ilshowall',
'id' => 'mw-listfiles-show-all',
unset( $query['ilshowall'] );
unset( $query['user'] );
- $form = new HTMLForm( $fields, $this->getContext() );
-
- $form->setMethod( 'get' );
- $form->setTitle( $this->getTitle() );
- $form->setId( 'mw-listfiles-form' );
- $form->setWrapperLegendMsg( 'listfiles' );
- $form->setSubmitTextMsg( 'table_pager_limit_submit' );
- $form->addHiddenFields( $query );
-
- $form->prepareForm();
- $form->displayForm( '' );
+ $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() );
+ $htmlForm
+ ->setMethod( 'get' )
+ ->setId( 'mw-listfiles-form' )
+ ->setTitle( $this->getTitle() )
+ ->setSubmitTextMsg( 'table_pager_limit_submit' )
+ ->setWrapperLegendMsg( 'listfiles' )
+ ->addHiddenFields( $query )
+ ->prepareForm()
+ ->displayForm( '' );
}
protected function getTableClass() {
namespace MediaWiki\Tidy;
+use MWException;
+
abstract class RaggettBase extends TidyDriverBase {
/**
* Generic interface for wrapping and unwrapping HTML for Dave Raggett's tidy.
break;
case 'actor':
// Make sure this thread sees its own changes
- if ( wfGetLB()->hasOrMadeRecentMasterChanges() ) {
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+ if ( $lb->hasOrMadeRecentMasterChanges() ) {
$flags |= self::READ_LATEST;
$this->queryFlagsUsed = $flags;
}
* site.
*
* @param string $val Input value to compare
- * @param string $salt Optional function-specific data for hashing
+ * @param string|array $salt Optional function-specific data for hashing
* @param WebRequest|null $request Object to use or null to use $wgRequest
* @param int $maxage Fail tokens older than this, in seconds
* @return bool Whether the token matches
* ignoring the suffix.
*
* @param string $val Input value to compare
- * @param string $salt Optional function-specific data for hashing
+ * @param string|array $salt Optional function-specific data for hashing
* @param WebRequest|null $request Object to use or null to use $wgRequest
* @param int $maxage Fail tokens older than this, in seconds
* @return bool Whether the token matches
case T_INTERFACE:
case T_TRAIT:
case T_DOUBLE_COLON:
+ case T_NEW:
$this->startToken = $token;
break;
case T_STRING:
// "self::static" which accesses the class name. It doens't define a new class.
$this->startToken = null;
break;
+ case T_NEW:
+ // Skip over T_CLASS after T_NEW because this is a PHP 7 anonymous class.
+ if ( !is_array( $token ) || $token[0] !== T_WHITESPACE ) {
+ $this->startToken = null;
+ }
+ break;
case T_NAMESPACE:
if ( $token === ';' || $token === '{' ) {
$this->namespace = $this->implodeTokens() . '\\';
* @ingroup Watchlist
*/
use MediaWiki\Linker\LinkTarget;
+use Wikimedia\Rdbms\DBUnexpectedError;
/**
* @author Addshore
*/
class CrhConverter extends LanguageConverter {
// Defines working character ranges
- const WORD_BEGINS = '\r\s\"\'\(\)\-<>\[\]\/.,:;!?';
- const WORD_ENDS = '\r\s\"\'\(\)\-<>\[\]\/.,:;!?';
// Cyrillic
const C_UC = 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'; # Crimean Tatar Cyrillic uppercase
const C_LC = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'; # Crimean Tatar Cyrillic lowercase
const C_CONS_UC = 'БВГДЖЗЙКЛМНПРСТФХЦЧШЩCÑ'; # Crimean Tatar Cyrillic + CÑ uppercase consonants
const C_CONS_LC = 'бвгджзйклмнпрстфхцчшщcñ'; # Crimean Tatar Cyrillic + CÑ lowercase consonants
- const C_M_CONS = 'бгкмпшcБГКМПШC'; # Crimean Tatar Cyrillic M-type consonants
+ const C_M_CONS = 'бгкмшcБГКМШC'; # Crimean Tatar Cyrillic M-type consonants
- # Crimean Tatar Cyrillic + CÑ consonants
+ // Crimean Tatar Cyrillic + CÑ consonants
const C_CONS = 'бвгджзйклмнпрстфхцчшщcñБВГДЖЗЙКЛМНПРСТФХЦЧШЩCÑ';
// Latin
const L_N_CONS_LC = 'çnrstz'; # Crimean Tatar Latin N-type lower case consonants
const L_N_CONS = 'çnrstzÇNRSTZ'; # Crimean Tatar Latin N-type consonants
const L_M_CONS = 'bcgkmpşBCGKMPŞ'; # Crimean Tatar Latin M-type consonants
- const L_CONS_UC = 'BCÇDFGHJKLMNÑPRSŞTVZ'; # Crimean Tatar Latin uppercase consonants
- const L_CONS_LC = 'bcçdfghjklmnñprsştvz'; # Crimean Tatar Latin lowercase consonants
- const L_CONS = 'bcçdfghjklmnñprsştvzBCÇDFGHJKLMNÑPRSŞTVZ'; # Crimean Tatar Latin consonants
+ const L_CONS_UC = 'BCÇDFGĞHJKLMNÑPQRSŞTVZ'; # Crimean Tatar Latin uppercase consonants
+ const L_CONS_LC = 'bcçdfgğhjklmnñpqrsştvz'; # Crimean Tatar Latin lowercase consonants
+ const L_CONS = 'bcçdfgğhjklmnñpqrsştvzBCÇDFGĞHJKLMNÑPQRSŞTVZ'; # Crimean Tatar Latin consonants
const L_VOW_UC = 'AÂEIİOÖUÜ'; # Crimean Tatar Latin uppercase vowels
const L_VOW = 'aâeıioöuüAÂEIİOÖUÜ'; # Crimean Tatar Latin vowels
const L_F_UC = 'EİÖÜ'; # Crimean Tatar Latin uppercase front vowels
];
- public $mExceptions = [];
+ public $mCyrl2LatnExceptions = [];
+ public $mLatn2CyrlExceptions = [];
+
public $mCyrl2LatnPatterns = [];
public $mLatn2CyrlPatterns = [];
+
public $mCyrlCleanUpRegexes = [];
public $mExceptionsLoaded = false;
$this->mExceptionsLoaded = true;
$crhExceptions = new MediaWiki\Languages\Data\CrhExceptions();
- list( $this->mExceptions, $this->mCyrl2LatnPatterns, $this->mLatn2CyrlPatterns,
- $this->mCyrlCleanUpRegexes ) = $crhExceptions->loadExceptions( self::L_LC . self::C_LC,
- self::L_UC . self::C_UC );
+ list( $this->mCyrl2LatnExceptions, $this->mLatn2CyrlExceptions,
+ $this->mCyrl2LatnPatterns, $this->mLatn2CyrlPatterns, $this->mCyrlCleanUpRegexes ) =
+ $crhExceptions->loadExceptions( self::L_LC . self::C_LC, self::L_UC . self::C_UC );
}
/**
* @return string
*/
function translate( $text, $toVariant ) {
- $letters = '';
switch ( $toVariant ) {
case 'crh-cyrl':
- $letters = self::L_UC . self::L_LC . "\'";
- break;
case 'crh-latn':
- $letters = self::C_UC . self::C_LC . "";
break;
default:
return $text;
- break;
}
if ( !$this->mTablesLoaded ) {
throw new MWException( "Broken variant table: " . implode( ',', array_keys( $this->mTables ) ) );
}
- // check for roman numbers like VII, XIX...
- // Lookahead assertion ensures $roman doesn't match the empty string
- $roman = '/^(?=[MDCLXVI])M{0,4}(C[DM]|D?C{0,3})(X[LC]|L?X{0,3})(I[VX]|V?I{0,3})$/u';
-
- # match any sub-string of the relevant letters and convert it
- $matches = preg_split( '/(\b|^)[^' . $letters . ']+(\b|$)/u',
- $text, -1, PREG_SPLIT_OFFSET_CAPTURE );
- $mstart = 0;
- $ret = '';
- foreach ( $matches as $m ) {
- # copy over the non-matching bit
- $ret .= substr( $text, $mstart, $m[1] - $mstart );
- # skip certain classes of strings
-
- if ( array_key_exists( $m[0], $this->mExceptions ) ) {
- # if it's an exception, just copy down the right answer
- $ret .= $this->mExceptions[$m[0]];
- } elseif ( ! $m[0] || # empty strings
- preg_match( $roman, $m[0] ) || # roman numerals
- preg_match( '/[^' . $letters . ']/', $m[0] ) # mixed orthography
- ) {
- $ret .= $m[0];
- } else {
- # convert according to the rules
- $token = $this->regsConverter( $m[0], $toVariant );
- $ret .= parent::translate( $token, $toVariant );
- }
- $mstart = $m[1] + strlen( $m[0] );
- }
-
- # pick up stray quote marks
switch ( $toVariant ) {
case 'crh-cyrl':
- $ret = strtr( $ret, [ '“' => '«', '”' => '»', ] );
- $ret = $this->regsConverter( $ret, 'cyrl-cleanup' );
- break;
- case 'crh-latn':
- $ret = strtr( $ret, [ '«' => '"', '»' => '"', ] );
- break;
- }
+ /* Check for roman numbers like VII, XIX...
+ * Only need to split on Roman numerals when converting to Cyrillic
+ * Lookahead assertion ensures $roman doesn't match the empty string, and
+ * non-period after first "Roman" character allows initials to be converted
+ */
+ $roman = '(?=[MDCLXVI]([^.]|$))M{0,4}(C[DM]|D?C{0,3})(X[LC]|L?X{0,3})(I[VX]|V?I{0,3})';
+
+ $breaks = '([^\w\x80-\xff])';
+
+ // allow for multiple Roman numerals in a row; rare but it happens
+ $romanRegex = '/^' . $roman . '$|^(' . $roman . $breaks . ')+|(' . $breaks . $roman . ')+$|' .
+ $breaks . '(' . $roman . $breaks . ')+/';
+
+ $matches = preg_split( $romanRegex, $text, -1, PREG_SPLIT_OFFSET_CAPTURE );
+ $mstart = 0;
+ $ret = '';
+ foreach ( $matches as $m ) {
+ // copy over Roman numerals
+ $ret .= substr( $text, $mstart, $m[1] - $mstart );
+
+ // process everything else
+ if ( $m[0] !== '' ) {
+ $ret .= $this->regsConverter( $m[0], $toVariant );
+ }
+
+ $mstart = $m[1] + strlen( $m[0] );
+ }
- return $ret;
+ return $ret;
+ default:
+ // Just process the whole string in one go
+ return $this->regsConverter( $text, $toVariant );
+ }
}
private function regsConverter( $text, $toVariant ) {
$rep = [];
switch ( $toVariant ) {
case 'crh-latn':
+ $text = strtr( $text, $this->mCyrl2LatnExceptions );
foreach ( $this->mCyrl2LatnPatterns as $pat => $rep ) {
$text = preg_replace( $pat, $rep, $text );
}
+ $text = parent::translate( $text, $toVariant );
+ $text = strtr( $text, [ '«' => '"', '»' => '"', ] );
return $text;
case 'crh-cyrl':
+ $text = strtr( $text, $this->mLatn2CyrlExceptions );
foreach ( $this->mLatn2CyrlPatterns as $pat => $rep ) {
$text = preg_replace( $pat, $rep, $text );
}
- return $text;
- case 'cyrl-cleanup':
+ $text = parent::translate( $text, $toVariant );
+ $text = strtr( $text, [ '“' => '«', '”' => '»', ] );
foreach ( $this->mCyrlCleanUpRegexes as $pat => $rep ) {
$text = preg_replace( $pat, $rep, $text );
}
$this->loadRegs();
}
- public $exceptionMap = [];
+ public $Cyrl2LatnExceptions = [];
+ public $Latn2CyrlExceptions = [];
+
public $Cyrl2LatnPatterns = [];
public $Latn2CyrlPatterns = [];
private function addMappings( $mapArray, &$A2B, &$B2A, $exactCase = false,
$prePat = '', $postPat = '' ) {
foreach ( $mapArray as $WordA => $WordB ) {
- $ucA = $this->myUc( $WordA );
- $ucWordA = $this->myUcWord( $WordA );
- $ucB = $this->myUc( $WordB );
- $ucWordB = $this->myUcWord( $WordB );
+ if ( ! $exactCase ) {
+ $ucA = $this->myUc( $WordA );
+ $ucWordA = $this->myUcWord( $WordA );
+ $ucB = $this->myUc( $WordB );
+ $ucWordB = $this->myUcWord( $WordB );
+ }
# if there are regexes, only map toward backregs
if ( ! preg_match( '/\$[1-9]/', $WordA ) ) {
function loadExceptions( $lcChars, $ucChars ) {
# init lc and uc, as needed
$this->initLcUc( $lcChars, $ucChars );
- # load C2L and L2C whole-word exceptions into the same array, since it's just a look up
- # no regex prefix/suffix needed
- $this->addMappings( $this->wordMappings, $this->exceptionMap, $this->exceptionMap );
- $this->addMappings( $this->exactCaseMappings, $this->exceptionMap, $this->exceptionMap, true );
- # load C2L and L2C bidirectional prefix mappings
+ # no regex prefix/suffix needed
+ $this->addMappings( $this->ManyToOneC2LMappings,
+ // reverse exception mapping order to handle many-to-one C2L mappings
+ $this->Latn2CyrlExceptions, $this->Cyrl2LatnExceptions );
+ $this->addMappings( $this->multiCaseMappings,
+ $this->Cyrl2LatnExceptions, $this->Latn2CyrlExceptions );
+ $this->addMappings( $this->exactCaseMappings,
+ $this->Cyrl2LatnExceptions, $this->Latn2CyrlExceptions, true );
+
+ # load C2L and L2C bidirectional affix mappings
$this->addMappings( $this->prefixMapping,
- $this->Cyrl2LatnPatterns, $this->Latn2CyrlPatterns, false, '/^', '/u' );
+ $this->Cyrl2LatnPatterns, $this->Latn2CyrlPatterns, false, '/\b', '/u' );
$this->addMappings( $this->suffixMapping,
- $this->Cyrl2LatnPatterns, $this->Latn2CyrlPatterns, false, '/', '$/u' );
+ $this->Cyrl2LatnPatterns, $this->Latn2CyrlPatterns, false, '/', '\b/u' );
# tack on one-way mappings to the ends of the prefix and suffix patterns
$this->Cyrl2LatnPatterns += $this->Cyrl2LatnRegexes;
$this->Latn2CyrlPatterns += $this->Latn2CyrlRegexes;
- return [ $this->exceptionMap, $this->Cyrl2LatnPatterns,
+ return [ $this->Cyrl2LatnExceptions, $this->Latn2CyrlExceptions, $this->Cyrl2LatnPatterns,
$this->Latn2CyrlPatterns, $this->CyrlCleanUpRegexes ];
}
- # map Cyrillic to Latin and back, whole word match only
+ # map Latin to Cyrillic and back, simple string match only (no regex)
# variants: all lowercase, all uppercase, first letter capitalized
- # items with capture group refs (e.g., $1) are only mapped from the
- # regex to the reference
- private $wordMappings = [
+ private $ManyToOneC2LMappings = [
+ # Carefully ordered many-to-one mappings
+ # these are ordered so C2L is correct (the later Latin one)
+ # see also L2C mappings below
+ 'fevqülade' => 'февкъульаде', 'fevqulade' => 'февкъульаде',
+ 'beyude' => 'бейуде', 'beyüde' => 'бейуде',
+ 'curat' => 'джурьат', 'cürat' => 'джурьат',
+ 'mesul' => 'месуль', 'mesül' => 'месуль',
+ ];
+
+ # map Cyrillic to Latin and back, simple string match only (no regex)
+ # variants: all lowercase, all uppercase, first letter capitalized
+ private $multiCaseMappings = [
- #### originally Cyrillic to Latin
+ #### Cyrillic to Latin
'аджыумер' => 'acıümer', 'аджыусеин' => 'acıüsein', 'алейкум' => 'aleyküm',
- 'бейуде' => 'beyüde', 'боливия' => 'boliviya', 'большевик' => 'bolşevik', 'борис' => 'boris',
- 'борнен' => 'bornen', 'бугун' => 'bugün', 'бузкесен' => 'buzkesen', 'буксир' => 'buksir',
- 'бульбуль' => 'bülbül', 'бульвар' => 'bulvar', 'бульдозер' => 'buldozer', 'бульон' => 'bulyon',
+ 'бозтюс' => 'boztüs', 'боливия' => 'boliviya', 'большевик' => 'bolşevik', 'борис' => 'boris',
+ 'борнен' => 'bornen', 'бублик' => 'bublik', 'буддизм' => 'buddizm', 'буддист' => 'buddist',
+ 'буженина' => 'bujenina', 'бузкесен' => 'buzkesen', 'букинист' => 'bukinist',
+ 'буксир' => 'buksir', 'бульбул' => 'bülbül', 'бульвар' => 'bulvar', 'бульдог' => 'buldog',
+ 'бульдозер' => 'buldozer', 'бульон' => 'bulyon', 'бумеранг' => 'bumerang',
'бунен' => 'bunen', 'буннен' => 'bunnen', 'бус-бутюн' => 'büs-bütün',
- 'бутерброд' => 'buterbrod', 'буфер' => 'bufer', 'буфет' => 'bufet', 'гонъюл' => 'göñül',
- 'горизонт' => 'gorizont', 'госпиталь' => 'gospital', 'гуливер' => 'guliver', 'гуна' => 'güna',
- 'гунях' => 'günâh', 'гургуль' => 'gürgül', 'гуя' => 'güya', 'демирёл' => 'demiryol',
- 'джуньджу' => 'cüncü', 'ёлнен' => 'yolnen', 'зумбуль' => 'zümbül', 'ильи' => 'ilyi', 'ишунь' =>
- 'işün', 'кодекс' => 'kodeks', 'кодифик' => 'kodifik', 'койлю' => 'köylü', 'коккоз' =>
- 'kökköz', 'коккозь' => 'kökköz', 'коккозю' => 'kökközü', 'кокос' => 'kokos',
- 'коллег' => 'kolleg', 'коллект' => 'kollekt', 'коллекц' => 'kollekts', 'кольцов' => 'koltsov',
- 'комбин' => 'kombin', 'комедия' => 'komediya', 'коменда' => 'komenda', 'комета' => 'kometa',
- 'комис' => 'komis', 'комит' => 'komit', 'комите' => 'komite', 'коммент' => 'komment',
- 'коммерс' => 'kommers', 'коммерц' => 'kommerts', 'компенс' => 'kompens', 'компил' => 'kompil',
- 'компьютер' => 'kompyuter', 'конвейер' => 'konveyer', 'конвен' => 'konven',
- 'конверт' => 'konvert', 'конденс' => 'kondens', 'кондитер' => 'konditer',
- 'кондиц' => 'kondits', 'коник' => 'konik', 'консерв' => 'konserv', 'контейнер' => 'konteyner',
- 'континент' => 'kontinent', 'конфе' => 'konfe', 'конфискац' => 'konfiskats',
- 'концен' => 'kontsen', 'концерт' => 'kontsert', 'конъюктур' => 'konyuktur',
- 'коньки' => 'konki', 'коньяк' => 'konyak', 'копирле' => 'kopirle', 'копия' => 'kopiya',
- 'корбекул' => 'körbekül', 'кореиз' => 'koreiz', 'коренн' => 'korenn', 'корея' => 'koreya',
- 'коридор' => 'koridor', 'корнеев' => 'korneyev', 'корре' => 'korre', 'корьбекул' =>
- 'körbekül', 'косме' => 'kosme', 'космик' => 'kosmik', 'костюм' => 'kostüm', 'котельн' =>
- 'koteln', 'котировка' => 'kotirovka', 'котлет' => 'kotlet', 'кочергин' => 'koçergin',
- 'коше' => 'köşe', 'кудрин' => 'kudrin', 'кузнец' => 'kuznets', 'кулинар' => 'kulinar',
- 'кулич' => 'kuliç', 'кульминац' => 'kulminats', 'культив' => 'kultiv',
- 'культура' => 'kultura', 'куркулет' => 'kürkület', 'курсив' => 'kursiv', 'кушку' => 'küşkü',
- 'куюк' => 'küyük', 'къарагоз' => 'qaragöz', 'къолязма' => 'qolyazma', 'къуртумер' =>
- 'qurtümer', 'къуртусеин' => 'qurtüsein', 'марьино' => 'maryino', 'медьюн' => 'medyun',
- 'месули' => 'mesüli', 'месуль' => 'mesül', 'мефкуре' => 'mefküre', 'могедек' => 'mögedek',
- 'муур' => 'müür', 'муче' => 'müçe', 'муюз' => 'müyüz', 'огнево' => 'ognevo',
- 'одеколон' => 'odekolon', 'одеса' => 'odesa', 'одесса' => 'odessa', 'озерки' => 'ozerki',
- 'озерн' => 'ozern', 'озёрн' => 'ozörn', 'океан' => 'okean', 'оленев' => 'olenev',
- 'олимп' => 'olimp', 'ольчер' => 'ölçer', 'онен' => 'onen', 'оннен' => 'onnen',
- 'опера' => 'opera', 'оптим' => 'optim', 'опци' => 'optsi', 'опция' => 'optsiya',
- 'орден' => 'orden', 'ордер' => 'order', 'ореанда' => 'oreanda', 'орех' => 'oreh',
- 'оригинал' => 'original', 'ориент' => 'oriyent', 'оркестр' => 'orkestr', 'орлин' => 'orlin',
- 'офис' => 'ofis', 'офицер' => 'ofitser', 'офсет' => 'ofset', 'оюннен' => 'oyunnen', 'побед' =>
- 'pobed', 'полево' => 'polevo', 'поли' => 'poli', 'полюшко' => 'polüşko',
- 'помидор' => 'pomidor', 'пониз' => 'poniz', 'порфир' => 'porfir', 'потелов' => 'potelov',
- 'почетн' => 'poçetn', 'почётн' => 'poçötn', 'публик' => 'publik', 'публиц' => 'publits',
- 'пушкин' => 'puşkin', 'сеитумер' => 'seitümer', 'сеитусеин' => 'seitüsein', 'сеитягъя' =>
- 'seityağya', 'сеитягья' => 'seityagya', 'сеитяхья' => 'seityahya', 'сеитяя' => 'seityaya',
+ 'бутерброд' => 'buterbrod', 'бутилен' => 'butilen', 'бутилир' => 'butilir',
+ 'буфер' => 'bufer', 'буфет' => 'bufet', 'гобелен' => 'gobelen', 'гомео' => 'gomeo',
+ 'горизонт' => 'gorizont', 'госпитал' => 'gospital', 'готтентот' => 'gottentot',
+ 'гофрир' => 'gofrir', 'губерн' => 'gubern', 'гуверн' => 'guvern', 'гугенот' => 'gugenot',
+ 'гуливер' => 'guliver', 'гуна' => 'güna', 'гунях' => 'günâh', 'гургуль' => 'gürgül',
+ 'гуя' => 'güya', 'дёрткуль' => 'dörtkül', 'джуньджу' => 'cüncü', 'ёлнен' => 'yolnen',
+ 'зумбуль' => 'zümbül', 'ильи' => 'ilyi', 'ишунь' => 'işün', 'ковер' => 'kover', 'код' => 'kod',
+ 'койлю' => 'köylü', 'кокагъач' => 'kökağaç', 'кокбаштанкъара' => 'kökbaştanqara',
+ 'кокгогерджин' => 'kökgögercin', 'кокдогъан' => 'kökdoğan', 'коккозю' => 'kökközü',
+ 'коккъузгъун' => 'kökquzğun', 'коклюш' => 'koklüş', 'кокташ' => 'köktaş',
+ 'коктогъан' => 'köktoğan', 'коктотай' => 'köktotay', 'коллег' => 'kolleg',
+ 'коллект' => 'kollekt', 'коллекц' => 'kollekts', 'колье' => 'kolye', 'кольраби' => 'kolrabi',
+ 'кольцов' => 'koltsov', 'комби' => 'kombi', 'комеди' => 'komedi', 'коменда' => 'komenda',
+ 'комета' => 'kometa', 'комив' => 'komiv', 'комис' => 'komis', 'комит' => 'komit',
+ 'комм' => 'komm', 'коммент' => 'komment', 'коммерс' => 'kommers', 'коммерц' => 'kommerts',
+ 'комп' => 'komp', 'конве' => 'konve', 'конгени' => 'kongeni', 'конденс' => 'kondens',
+ 'кондил' => 'kondil', 'кондитер' => 'konditer', 'кондиц' => 'kondits', 'коник' => 'konik',
+ 'конкис' => 'konkis', 'консерв' => 'konserv', 'конси' => 'konsi', 'контейнер' => 'konteyner',
+ 'конти' => 'konti', 'конфе' => 'konfe', 'конфи' => 'konfi', 'конце' => 'kontse',
+ 'конъю' => 'konyu', 'коньки' => 'konki', 'коньяк' => 'konyak', 'копирле' => 'kopirle',
+ 'копия' => 'kopiya', 'корде' => 'korde', 'кореиз' => 'koreiz', 'коренн' => 'korenn',
+ 'корея' => 'koreya', 'кориа' => 'koria', 'коридор' => 'koridor', 'корне' => 'korne',
+ 'корнеев' => 'korneyev', 'корни' => 'korni', 'корре' => 'korre', 'косме' => 'kosme',
+ 'космик' => 'kosmik', 'костюм' => 'kostüm', 'котельн' => 'koteln', 'котир' => 'kotir',
+ 'котлет' => 'kotlet', 'кочерг' => 'koçerg', 'коше' => 'köşe', 'куби' => 'kubi',
+ 'кудрин' => 'kudrin', 'кузнец' => 'kuznets', 'кулинар' => 'kulinar', 'кулич' => 'kuliç',
+ 'кульмин' => 'kulmin', 'культаш' => 'kültaş', 'культе' => 'külte', 'культ' => 'kult',
+ 'куркулет' => 'kürkület', 'курсив' => 'kursiv', 'кушет' => 'kuşet', 'кушку' => 'küşkü',
+ 'куюк' => 'küyük', 'къолязма' => 'qolyazma', 'къуртумер' => 'qurtümer',
+ 'къуртусеин' => 'qurtüsein', 'медьюн' => 'medyun', 'месули' => 'mesüli',
+ 'мефкуре' => 'mefküre', 'могедек' => 'mögedek', 'мумиё' => 'mumiyo', 'мумиф' => 'mumif',
+ 'муче' => 'müçe', 'муюз' => 'müyüz', 'нумюне' => 'nümüne', 'обел' => 'obel', 'обер' => 'ober',
+ 'обли' => 'obli', 'обсе' => 'obse', 'обт' => 'obt', 'огне' => 'ogne', 'одеколон' => 'odekolon',
+ 'одеса' => 'odesa', 'одесса' => 'odessa', 'озерки' => 'ozerki', 'озерн' => 'ozern',
+ 'озёрн' => 'ozörn', 'озюя' => 'özüya', 'океан' => 'okean', 'окси' => 'oksi',
+ 'октет' => 'oktet', 'олеа' => 'olea', 'олеи' => 'olei', 'оленев' => 'olenev', 'олив' => 'oliv',
+ 'олиг' => 'olig', 'олимп' => 'olimp', 'олиф' => 'olif', 'ольчер' => 'ölçer', 'омле' => 'omle',
+ 'онен' => 'onen', 'оннен' => 'onnen', 'опера' => 'opera', 'опере' => 'opere',
+ 'оптим' => 'optim', 'опци' => 'optsi', 'орби' => 'orbi', 'орден' => 'orden',
+ 'ордер' => 'order', 'ордин' => 'ordin', 'ореа' => 'orea', 'орех' => 'oreh',
+ 'ориент' => 'oriyent', 'оркестр' => 'orkestr', 'орлин' => 'orlin', 'орни' => 'orni',
+ 'орхи' => 'orhi', 'осци' => 'ostsi', 'офис' => 'ofis', 'офиц' => 'ofits', 'офсет' => 'ofset',
+ 'очерк' => 'oçerk', 'оюннен' => 'oyunnen', 'побед' => 'pobed', 'полево' => 'polevo',
+ 'поли' => 'poli', 'полюшко' => 'polüşko', 'помидор' => 'pomidor', 'пониз' => 'poniz',
+ 'порфир' => 'porfir', 'потелов' => 'potelov', 'потюк' => 'pötük', 'почетн' => 'poçetn',
+ 'почётн' => 'poçötn', 'пукле' => 'pükle', 'пуркю' => 'pürkü', 'пурумют' => 'purümüt',
+ 'пускул' => 'püskül', 'пускур' => 'püskür', 'пусюр' => 'püsür', 'пуфле' => 'püfle',
'сейитумер' => 'seyitümer', 'сейитусеин' => 'seyitüsein', 'сейитягъя' => 'seyityağya',
'сейитягья' => 'seyityagya', 'сейитяхья' => 'seyityahya', 'сейитяя' => 'seyityaya',
- 'ультимат' => 'ultimat', 'ультра' => 'ultra', 'ульянов' => 'ulyanov', 'универ' => 'univer',
- 'уника' => 'unika', 'унтер' => 'unter', 'урьян' => 'uryan', 'уткин' => 'utkin', 'учебн' =>
- 'uçebn', 'шовини' => 'şovini', 'шоссе' => 'şosse', 'шубин' => 'şubin', 'шунен' => 'şunen',
- 'шуннен' => 'şunnen', 'щёлкино' => 'şçolkino', 'эмирусеин' => 'emirüsein',
- 'юзбашы' => 'yüzbaşı', 'юзйыл' => 'yüzyıl', 'юртер' => 'yurter', 'ющенко' => 'yuşçenko',
-
- 'кою' => 'köyü', 'кок' => 'kök', 'ком-кок' => 'köm-kök', 'коп' => 'köp', 'ог' => 'ög',
- 'юрип' => 'yürip', 'юз' => 'yüz', 'юк' => 'yük', 'буюп' => 'büyüp', 'буюк' => 'büyük',
- 'джонк' => 'cönk', 'джонкю' => 'cönkü', 'устке' => 'üstke', 'устте' => 'üstte',
- 'усттен' => 'üstten',
-
- # шофёр needs to come after шофер to override it in the Latin-to-Cyrillic direction
- 'шофер' => 'şoför',
- 'шофёр' => 'şoför',
-
- #### originally Latin to Cyrillic (deduped from above)
+ 'сеитумер' => 'seitümer', 'сеитусеин' => 'seitüsein', 'сеитягъя' => 'seityağya',
+ 'сеитягья' => 'seityagya', 'сеитяхья' => 'seityahya', 'сеитяя' => 'seityaya',
+ 'сурет' => 'süret', 'увертюра' => 'uvertüra', 'угле' => 'ugle', 'узвий' => 'uzviy',
+ 'улица' => 'ulitsa', 'ультимат' => 'ultimat', 'ультра' => 'ultra', 'ульянов' => 'ulyanov',
+ 'универ' => 'univer', 'уник' => 'unik', 'унис' => 'unis', 'унит' => 'unit', 'униф' => 'unif',
+ 'унтер' => 'unter', 'урьян' => 'uryan', 'утил' => 'util', 'уткин' => 'utkin',
+ 'учебн' => 'uçebn', 'шовини' => 'şovini', 'шоссе' => 'şosse', 'шубин' => 'şubin',
+ 'шунен' => 'şunen', 'шуннен' => 'şunnen', 'шунчюн' => 'şunçün', 'щёлкино' => 'şçolkino',
+ 'эмирусеин' => 'emirüsein', 'юзбашы' => 'yüzbaşı', 'юзйыл' => 'yüzyıl', 'юртер' => 'yurter',
+ 'ющенко' => 'yuşçenko',
+
+ ### Carefully ordered many-to-one mappings
+ # these are ordered so L2C is correct (the later Cyrillic one)
+ # see also $ManyToOneC2LMappings above for C2L
+ 'шофер' => 'şoför', 'шофёр' => 'şoför',
+ 'бугун' => 'bugün', 'бугунь' => 'bugün',
+ 'демирёл' => 'demiryol', 'демиръёл' => 'demiryol',
+ 'гонъюл' => 'göñül', 'гонъюль' => 'göñül',
+ 'коккоз' => 'kökköz', 'коккозь' => 'kökköz',
+ 'корбекул' => 'körbekül', 'корьбекул' => 'körbekül', 'корьбекуль' => 'körbekül',
+ 'муур' => 'müür', 'муурь' => 'müür',
+ 'оригинал' => 'original', 'оригиналь' => 'original',
+ 'пускю' => 'püskü', 'пуськю' => 'püskü',
+ 'къарагоз' => 'qaragöz', 'къарагозь' => 'qaragöz',
+ 'етсин' => 'yetsin', 'етсин' => 'etsin',
+
+ #### Latin to Cyrillic (deduped from above)
# слова на -аль
# words in -аль
'истикъбаль' => 'istiqbal', 'истикъляль' => 'istiqlâl', 'италия' => 'italiya',
'италья' => 'italya', 'ишгъаль' => 'işğal', 'кафедраль' => 'kafedral', 'казуаль' => 'kazual',
'коллегиаль' => 'kollegial', 'колоссаль' => 'kolossal', 'коммуналь' => 'kommunal',
- 'кординаль' => 'kordinal', 'криминаль' => 'kriminal', 'легаль' => 'legal', 'леталь' => 'letal',
- 'либеÑ\80алÑ\8c' => 'liberal', 'локалÑ\8c' => 'lokal', 'магиÑ\81Ñ\82Ñ\80алÑ\8c' => 'magistral',
- 'материаль' => 'material', 'машиналь' => 'maşinal', 'меаль' => 'meal',
- 'медалÑ\8cон' => 'medalyon', 'медалÑ\8c' => 'medal', 'меÑ\80идионалÑ\8c' => 'meridional',
- 'меÑ\88Ñ\8aалÑ\8c' => 'meÅ\9fal', 'минеÑ\80алÑ\8c' => 'mineral', 'минималÑ\8c' => 'minimal', 'миÑ\81алÑ\8c' => 'misal',
- 'модалÑ\8c' => 'modal', 'мÑ\83зÑ\8bкалÑ\8c' => 'muzıkal', 'номиналÑ\8c' => 'nominal', 'ноÑ\80малÑ\8c' => 'normal',
- 'опÑ\82ималÑ\8c' => 'optimal', 'оÑ\80биÑ\82алÑ\8c' => 'orbital', 'оÑ\80игиналÑ\8c' => 'original',
- 'педалÑ\8c' => 'pedal', 'пÑ\80опоÑ\80Ñ\86ионалÑ\8c' => 'proportsional', 'пÑ\80оÑ\84еÑ\81Ñ\81ионалÑ\8c' => 'professional',
- 'радикаль' => 'radikal', 'рациональ' => 'ratsional', 'реаль' => 'real',
- 'региональ' => 'regional', 'суаль' => 'sual', 'шималь' => 'şimal',
+ 'кординаль' => 'kordinal', 'криминаль' => 'kriminal', 'легаль' => 'legal',
+ 'леÑ\82алÑ\8c' => 'letal', 'либеÑ\80алÑ\8c' => 'liberal', 'локалÑ\8c' => 'lokal',
+ 'магистраль' => 'magistral', 'материаль' => 'material', 'машиналь' => 'maşinal',
+ 'меалÑ\8c' => 'meal', 'медалÑ\8cон' => 'medalyon', 'медалÑ\8c' => 'medal',
+ 'меÑ\80идионалÑ\8c' => 'meridional', 'меÑ\88Ñ\8aалÑ\8c' => 'meÅ\9fal', 'минеÑ\80алÑ\8c' => 'mineral',
+ 'минималÑ\8c' => 'minimal', 'миÑ\81алÑ\8c' => 'misal', 'модалÑ\8c' => 'modal', 'мÑ\83зÑ\8bкалÑ\8c' => 'muzıkal',
+ 'номиналÑ\8c' => 'nominal', 'ноÑ\80малÑ\8c' => 'normal', 'опÑ\82ималÑ\8c' => 'optimal',
+ 'оÑ\80биÑ\82алÑ\8c' => 'orbital', 'педалÑ\8c' => 'pedal', 'пÑ\80опоÑ\80Ñ\86ионалÑ\8c' => 'proportsional',
+ 'профессиональ' => 'professional', 'радикаль' => 'radikal', 'рациональ' => 'ratsional',
+ 'Ñ\80еалÑ\8c' => 'real', 'Ñ\80егионалÑ\8c' => 'regional', 'Ñ\81Ñ\83алÑ\8c' => 'sual', 'Ñ\88ималÑ\8c' => 'Å\9fimal',
'территориаль' => 'territorial', 'тимсаль' => 'timsal', 'тоталь' => 'total',
'уникаль' => 'unikal', 'универсаль' => 'universal', 'вертикаль' => 'vertikal',
'виртуаль' => 'virtual', 'визуаль' => 'vizual', 'вуаль' => 'vual', 'зональ' => 'zonal',
- 'зуаль' => 'zual',
+ 'зуаль' => 'zual', 'италь' => 'ital',
# слова с мягким знаком перед а, о, у, э
# Words with a soft sign before а, о, у, э
- 'бильакис' => 'bilakis', 'маальэсеф' => 'maalesef',
- 'мельун' => 'melun', 'озьара' => 'özara', 'вельасыл' => 'velasıl',
- 'ельаякъ' => 'yelayaq',
- # these are ordered so C2L is correct (the later Latin one)
- 'февкъульаде' => 'fevqülade','февкъульаде' => 'fevqulade',
+ 'бильакис' => 'bilakis', 'маальэсеф' => 'maalesef', 'мельун' => 'melun', 'озьара' => 'özara',
+ 'вельасыл' => 'velasıl', 'ельаякъ' => 'yelayaq',
# другие слова с мягким знаком
# Other words with a soft sign
'альбатрос' => 'albatros', 'альбинос' => 'albinos', 'альбом' => 'albom',
'альбумин' => 'albumin', 'алфавит' => 'alfavit', 'альфа' => 'alfa', 'альманах' => 'almanah',
- 'альпинист' => 'alpinist', 'альтерн' => 'altern', 'альтру' => 'altru', 'альвеола' => 'alveola',
- 'анÑ\81амблÑ\8c' => 'ansambl', 'анÑ\8cане' => 'anane', 'аÑ\81Ñ\84алÑ\8cÑ\82' => 'asfalt', 'балÑ\8cнео' => 'balneo',
- 'бааÑ\80Ñ\8c' => 'baar', 'базалÑ\8cÑ\82' => 'bazalt', 'биноклÑ\8c' => 'binokl', 'джÑ\83Ñ\80Ñ\8cаÑ\82' => 'curat',
- 'джÑ\83Ñ\80Ñ\8cаÑ\82' => 'cürat', 'девалÑ\8cв' => 'devalv', 'Ñ\84акÑ\83лÑ\8cÑ\82' => 'fakult', 'Ñ\84алÑ\8cÑ\81иÑ\84' => 'falsif',
- 'фольклор' => 'folklor', 'гальван' => 'galvan', 'геральд' => 'gerald', 'женьшень' => 'jenşen',
+ 'альпинист' => 'alpinist', 'альтерн' => 'altern', 'альтру' => 'altru',
+ 'алÑ\8cвеола' => 'alveola', 'анÑ\81амблÑ\8c' => 'ansambl', 'анÑ\8cане' => 'anane', 'аÑ\81Ñ\84алÑ\8cÑ\82' => 'asfalt',
+ 'балÑ\8cнео' => 'balneo', 'бааÑ\80Ñ\8c' => 'baar', 'базалÑ\8cÑ\82' => 'bazalt', 'биноклÑ\8c' => 'binokl',
+ 'девалÑ\8cв' => 'devalv', 'Ñ\84акÑ\83лÑ\8cÑ\82' => 'fakult', 'Ñ\84алÑ\8cÑ\81иÑ\84' => 'falsif', 'Ñ\84олÑ\8cклоÑ\80' => 'folklor',
+ 'гальван' => 'galvan', 'геральд' => 'gerald', 'женьшень' => 'jenşen',
'инвентарь' => 'inventar', 'кальк' => 'kalk', 'кальмар' => 'kalmar', 'консульт' => 'konsult',
- 'контроль' => 'kontrol', 'кульмин' => 'kulmin', 'культур' => 'kultur', 'лагерь' => 'lager',
- 'макъбуль' => 'maqbul', 'макъуль' => 'maqul', 'мальт' => 'malt', 'мальземе' => 'malzeme',
- 'меджуль' => 'mecul', 'мешгуль' => 'meşgül', 'мешгъуль' => 'meşğul', 'мульти' => 'multi',
+ 'контроль' => 'kontrol', 'культур' => 'kultur', 'лагерь' => 'lager', 'макъбуль' => 'maqbul',
+ 'макъуль' => 'maqul', 'мальт' => 'malt', 'мальземе' => 'malzeme', 'меджуль' => 'mecul',
+ 'мешгуль' => 'meşgül', 'мешгъуль' => 'meşğul', 'мульти' => 'multi',
'мусульман' => 'musulman', 'нефть' => 'neft', 'пальто' => 'palto', 'пароль' => 'parol',
'патруль' => 'patrul', 'пенальти' => 'penalti', 'къальби' => 'qalbi', 'къальпке' => 'qalpke',
'къальплер' => 'qalpler', 'къальпни' => 'qalpni', 'къальпте' => 'qalpte', 'къаарь' => 'qaar',
# слова с твёрдым знаком
# Words with a solid sign
'бидъат' => 'bidat', 'бузъюрек' => 'buzyürek', 'атешъюрек' => 'ateşyürek',
- 'алÑ\8aÑ\8fнакÑ\8a' => 'alyanaq', 'демиÑ\80Ñ\8aÑ\91л' => 'demiryol', 'деÑ\80Ñ\8aал' => 'deral', 'инÑ\8aекÑ\86' => 'inyekts',
- 'меÑ\84Ñ\8aÑ\83м' => 'mefum', 'меÑ\88Ñ\8aÑ\83м' => 'meÅ\9fum', 'обÑ\8aекÑ\82' => 'obyekt', 'Ñ\80азÑ\8aезд' => 'razyezd',
- 'Ñ\81Ñ\83бÑ\8aекÑ\82' => 'subyekt', 'Ñ\85авÑ\8aÑ\8fÑ\80' => 'havyar', 'Ñ\8fмÑ\8aÑ\8fм' => 'yamyam',
+ 'алÑ\8aÑ\8fнакÑ\8a' => 'alyanaq', 'инÑ\8aекÑ\86' => 'inyekts', 'меÑ\84Ñ\8aÑ\83м' => 'mefum', 'меÑ\88Ñ\8aÑ\83м' => 'meÅ\9fum',
+ 'обÑ\8aекÑ\82' => 'obyekt', 'Ñ\80азÑ\8aезд' => 'razyezd', 'Ñ\81Ñ\83бÑ\8aекÑ\82' => 'subyekt', 'Ñ\85авÑ\8aÑ\8fÑ\80' => 'havyar',
+ 'ямъям' => 'yamyam',
# слова с буквой щ
# words with щ
'ящик' => 'yaşçik', 'мещан' => 'meşçan',
- # слова с буквой ц
+ # слова с ц
# words with ц
'акциз' => 'aktsiz', 'ацет' => 'atset', 'блиц' => 'blits', 'бруцеллёз' => 'brutsellöz',
'доцент' => 'dotsent', 'фармацевт' => 'farmatsevt', 'глицер' => 'glitser',
'люцерна' => 'lütserna', 'лицей' => 'litsey', 'меццо' => 'metstso', 'наци' => 'natsi',
'проце' => 'protse', 'рецеп' => 'retsep', 'реценз' => 'retsenz', 'теплица' => 'teplitsa',
- 'виÑ\86е' => 'vitse', 'Ñ\86епÑ\81' => 'tseps', 'Ñ\88вейÑ\86аÑ\80' => 'Å\9fveytsar',
+ 'вице' => 'vitse', 'швейцар' => 'şveytsar',
- # слова без буквы тс
+ # слова с тс
# words with тс
'агъартс' => 'ağarts', 'агъыртс' => 'ağırts', 'бильдиртс' => 'bildirts', 'битсин' => 'bitsin',
'буюльтс' => 'büyülts', 'буютс' => 'büyüts', 'гебертс' => 'geberts', 'делиртс' => 'delirts',
'кучертс' => 'küçerts', 'кучюльтс' => 'küçülts', 'пертсин' => 'pertsin', 'къайтс' => 'qayts',
'къутсуз' => 'qutsuz', 'орьтс' => 'örts', 'отьс' => 'öts', 'тартс' => 'tarts',
'тутсун' => 'tutsun', 'тюнъюльтс' => 'tüñülts', 'тюртс' => 'türts', 'янъартс' => 'yañarts',
- 'ебеÑ\80Ñ\82Ñ\81' => 'yeberts', 'еÑ\82Ñ\81ин' => 'yetsin', 'еÑ\88еÑ\80Ñ\82Ñ\81' => 'yeÅ\9ferts', 'йиÑ\80иÑ\82Ñ\81' => 'yirits',
+ 'ебертс' => 'yeberts', 'ешертс' => 'yeşerts', 'йиритс' => 'yirits',
# разные исключения
# different exceptions
- 'бейуде' => 'beyude', 'бугунь' => 'bugün', 'бюджет' => 'bücet', 'бюллет' => 'büllet',
- 'бюро' => 'büro', 'бюст' => 'büst', 'джонк' => 'cönk', 'диалог' => 'dialog',
- 'гонъюль' => 'göñül', 'ханымэфенди' => 'hanımefendi', 'каньон' => 'kanyon', 'кирил' => 'kiril',
- 'кирил' => 'kirill', 'кёрджа' => 'körca', 'кой' => 'köy', 'кулеръюзь' => 'küleryüz',
- 'маалле' => 'маальle', 'майор' => 'mayor', 'маниал' => 'manиаль', 'мефкуре' => 'mefküre',
- 'месуль' => 'mesul', 'месуль' => 'mesül', 'муурь' => 'müür',
- 'нормала' => 'нормальa', 'нумюне' => 'nümüne', 'проект' => 'proekt', 'район' => 'rayon',
- 'сойады' => 'soyadı', 'спортсмен' => 'sportsmen', 'услюп' => 'üslüp', 'услюб' => 'üslüb',
- 'вакъиал' => 'vaqиаль', 'юзйыллыкъ' => 'yüzyıllıq',
+ 'бюджет' => 'bücet', 'бюллет' => 'büllet', 'бюро' => 'büro', 'бюст' => 'büst',
+ 'диалог' => 'dialog', 'ханымэфенди' => 'hanımefendi', 'каньон' => 'kanyon',
+ 'кирил' => 'kiril', 'кирилл' => 'kirill', 'кёрджа' => 'körca', 'коy' => 'köy',
+ 'кулеръюзь' => 'küleryüz', 'маалле' => 'маальle', 'майор' => 'mayor', 'маниал' => 'manиаль',
+ 'нормала' => 'нормальa', 'проект' => 'proekt', 'район' => 'rayon', 'сойады' => 'soyadı',
+ 'спортсмен' => 'sportsmen', 'услюп' => 'üslüp', 'услюб' => 'üslüb', 'вакъиал' => 'vaqиаль',
+ 'юзйыллыкъ' => 'yüzyıllıq', 'койот' => 'koyot',
# имена собственные
# proper names
- 'адольф' => 'adolf', 'альберт' => 'albert', 'бешуй' => 'beşüy', 'эмирусеин' => 'emirüsein',
- 'флотск' => 'flotsk', 'гайана' => 'gayana', 'грэсовский' => 'gresovskiy', 'гриц' => 'grits',
- 'гурджи' => 'gürci', 'игорь' => 'igor', 'ильич' => 'ilyiç', 'ильин' => 'ilyin',
- 'исмаил' => 'ismail', 'киттс' => 'kitts', 'комсомольск' => 'komsomolsk',
- 'корьбекулю' => 'körbekülü', 'корьбекуль' => 'körbekül', 'куницын' => 'kunitsın',
- 'львив' => 'lviv', 'львов' => 'lvov', 'марьино' => 'maryino', 'махульдюр' => 'mahuldür',
- 'павел' => 'pavel', 'пантикапейон' => 'pantikapeyon', 'къарагозь' => 'qaragöz',
- 'къуртсейит' => 'qurtseyit', 'къуртсеит' => 'qurtseit', 'къуртумер' => 'qurtümer',
- 'сейитумер' => 'seyitümer', 'сеитумер' => 'seitümer', 'смаил' => 'smail',
- 'советск' => 'sovetsk', 'шемьи-заде' => 'şemi-zade', 'щёлкино' => 'şçolkino',
- 'тсвана' => 'tsvana', 'учьэвли' => 'üçevli', 'йохан' => 'yohan', 'йорк' => 'york',
- 'ющенко' => 'yuşçenko', 'льная' => 'lnaya', 'льное' => 'lnoye', 'льный' => 'lnıy',
- 'льская' => 'lskaya', 'льский' => 'lskiy', 'льское' => 'lskoye', 'ополь' => 'opol',
+ 'адольф' => 'adolf', 'альберт' => 'albert', 'бешуй' => 'beşüy', 'флотск' => 'flotsk',
+ 'гайана' => 'gayana', 'грэсовский' => 'gresovskiy', 'гриц' => 'grits', 'гурджи' => 'gürci',
+ 'игорь' => 'igor', 'ильич' => 'ilyiç', 'ильин' => 'ilyin', 'исмаил' => 'ismail',
+ 'киттс' => 'kitts', 'комсомольск' => 'komsomolsk', 'корьбекулю' => 'körbekülü',
+ 'куницын' => 'kunitsın', 'львив' => 'lviv', 'львов' => 'lvov', 'марьино' => 'maryino',
+ 'махульдюр' => 'mahuldür', 'павел' => 'pavel', 'пантикапейон' => 'pantikapeyon',
+ 'къуртсейит' => 'qurtseyit', 'къуртсеит' => 'qurtseit', 'смаил' => 'smail',
+ 'советск' => 'sovetsk', 'шемьи-заде' => 'şemi-zade', 'тсвана' => 'tsvana',
+ 'учьэвли' => 'üçevli', 'йохан' => 'yohan', 'йорк' => 'york', 'винныця' => 'vinnıtsâ',
+ 'винница' => 'vinnitsa', 'хмельницк' => 'hmelnitsk', 'хмельныцк' => 'hmelnıtsk',
+ 'зайце' => 'zaytse', 'чистеньк' => 'çistenk', 'кольчуг' => 'kolçug', 'ручьи' => 'ruçyi',
+ 'ботсвана' => 'botsvana', 'большой' => 'bolşoy', 'большое' => 'bolşoye',
+ 'большая' => 'bolşaya', 'ущелье' => 'uşçelye', 'ущельное' => 'uşçelnoye',
+ 'предущельное' => 'preduşçelnoye', 'новенькое' => 'novenkoye', 'новосельц' => 'novoselts',
+ 'мелко' => 'melko', 'овощ' => 'ovoşç', 'перепёлк' => 'perepölk', 'рощин' => 'roşçin',
+ 'братск' => 'bratsk', 'краснофлотск' => 'krasnoflotsk', 'синицин' => 'sinitsin',
+ 'синицын' => 'sinitsın', 'льгов' => 'lgov', 'желто' => 'jelto', 'жёлт' => 'jölt',
+ 'пермь' => 'perm', 'солдатск' => 'soldatsk', 'кольцо' => 'koltso', 'шелко' => 'şelko',
+ 'охотск' => 'ohotsk', 'марий эл' => 'mariy el', 'мариуполь' => 'mariupol',
+ 'белгород' => 'belgorod', 'иркутск' => 'irkutsk', 'Иркутск' => 'İrkutsk', 'орёл' => 'oröl',
+ 'рязанск' => 'râzansk', 'рязань' => 'râzan', 'тверск' => 'tversk', 'тверь' => 'tver',
+ 'ярославль' => 'yaroslavl', 'благовеще' => 'blagoveşçe', 'мальдив' => 'maldiv',
+ 'бальбек' => 'balbek', 'альчик' => 'alçik', 'харьков' => 'harkov', 'волынск' => 'volınsk',
+ 'волынь' => 'volın',
- # originally Latin to Cyrillic, deduped from above
- 'ань' => 'an', 'аньге' => 'ange', 'аньде' => 'ande', 'аньки' => 'anki', 'кёр' => 'kör',
- 'мэр' => 'mer', 'этсин' => 'etsin',
-
- # exceptions added after speaker review
- # see https://www.mediawiki.org/wiki/User:TJones_(WMF)/T23582
- 'аджизленювинъиз' => 'acizlenüviñiz', 'акъшам' => 'aqşam', 'алчакъгонъюлли' => 'alçaqgöñülli',
- 'аньанелер' => 'ananeler', 'аньанелеримиз' => 'ananelerimiz',
- 'аньанелеримизден' => 'ananelerimizden', 'аньанелеримизни' => 'ananelerimizni',
- 'аньанели' => 'ananeli', 'асфальтке' => 'asfaltke', 'баарьде' => 'baarde', 'бахтсыз' => 'bahtsız',
- 'берилюви' => 'berilüvi', 'берювден' => 'berüvden', 'берювни' => 'berüvni',
- 'большевиклер' => 'bolşevikler', 'большевиклерге' => 'bolşeviklerge', 'болюк' => 'bölük',
- 'болюнген' => 'bölüngen', 'болюнгенини' => 'bölüngenini', 'болюшип' => 'bölüşip',
- 'бугуннинъ' => 'bugünniñ', 'бугуньден' => 'bugünden', 'бугуньки' => 'bugünki',
- 'букюльген' => 'bükülgen', 'букюльди' => 'büküldi', 'буллюр' => 'büllür',
- 'бурюмчик' => 'bürümçik', 'бурюнген' => 'bürüngen', 'бутюн' => 'bütün', 'бутюнлей' => 'bütünley',
- 'буюген' => 'büyügen', 'буюй' => 'büyüy', 'волость' => 'volost', 'волостьларгъа' => 'volostlarğa',
- 'гонъюлини' => 'göñülini', 'гонъюлли' => 'göñülli', 'гонъюллилер' => 'göñülliler',
- 'госпиталинде' => 'gospitalinde', 'госпитальге' => 'gospitalge', 'госпитальде' => 'gospitalde',
- 'гренадёр' => 'grenadör', 'гугюм' => 'gügüm', 'гугюмлер' => 'gügümler',
- 'гугюмлери' => 'gügümleri', 'гугюмлерини' => 'gügümlerini', 'гурьсюльди' => 'gürsüldi',
- 'гурюльдештилер' => 'gürüldeştiler', 'гурюльти' => 'gürülti', 'гурюльтили' => 'gürültili',
- 'гурюльтисидир' => 'gürültisidir', 'дарульмуаллиминде' => 'darülmualliminde',
- 'дарульмуаллимининде' => 'darülmuallimininde', 'дарульмуаллиминнинъ' => 'darülmualliminniñ',
- 'дёгюльген' => 'dögülgen', 'декабрьде' => 'dekabrde', 'дёндюрилип' => 'döndürilip',
- 'дёнермиз' => 'dönermiz', 'дёнмектелер' => 'dönmekteler', 'денъишюв' => 'deñişüv',
- 'дёрдю' => 'dördü', 'дёрдюмиз' => 'dördümiz', 'дёрдюнджи' => 'dördünci', 'дёрт' => 'dört',
- 'дертлешювге' => 'dertleşüvge', 'джесюр' => 'cesür', 'джесюране' => 'cesürane',
- 'джесюрликлерини' => 'cesürliklerini', 'джонегенлерини' => 'cönegenlerini',
- 'джонедим' => 'cönedim', 'джонейлер' => 'cöneyler', 'джурьатсызлыгъына' => 'cüratsızlığına',
- 'дюгюнлер' => 'dügünler', 'дюгюнлерле' => 'dügünlerle', 'дюдюк' => 'düdük', 'дюльбер' => 'dülber',
- 'дюльбери' => 'dülberi', 'дюльберлер' => 'dülberler', 'дюльберлернинъ' => 'dülberlerniñ',
- 'дюльгер' => 'dülger', 'дюльгерге' => 'dülgerge', 'дюльгерлернинъки' => 'dülgerlerniñki',
- 'дюльгерни' => 'dülgerni', 'дюльгернинъ' => 'dülgerniñ', 'дюмбюрдетти' => 'dümbürdetti',
- 'дюмен' => 'dümen', 'дюмени' => 'dümeni', 'дюнья' => 'dünya', 'дюньявий' => 'dünyaviy',
- 'дюньяда' => 'dünyada', 'дюньяларгъа' => 'dünyalarğa', 'дюньяларда' => 'dünyalarda',
- 'дюньяны' => 'dünyanı', 'дюньянынъ' => 'dünyanıñ', 'дюньясы' => 'dünyası',
- 'ельаякълылар' => 'yelayaqlılar', 'елькъуваны' => 'yelquvanı', 'ильич' => 'i̇liç',
- 'ичюн' => 'içün', 'ичюнми' => 'içünmi', 'келюви' => 'kelüvi', 'келювини' => 'kelüvini',
- 'келювинъизде' => 'kelüviñizde', 'келювни' => 'kelüvni', 'кемирювлер' => 'kemirüvler',
- 'кесювде' => 'kesüvde', 'кетюв' => 'ketüv', 'кетювге' => 'ketüvge', 'кетюви' => 'ketüvi',
- 'кетювимни' => 'ketüvimni', 'кетювлер' => 'ketüvler', 'кетювлери' => 'ketüvleri',
- 'кетювлеринънинъ' => 'ketüvleriñniñ', 'кетювнинъ' => 'ketüvniñ', 'кирюв' => 'kirüv',
- 'князь' => 'knâz', 'козькъапакъларыны' => 'közqapaqlarını', 'козьлю' => 'közlü', 'козю' => 'közü',
- 'козюме' => 'közüme', 'козюнде' => 'közünde', 'козюне' => 'közüne', 'козюнен' => 'közünen',
- 'козюнинъ' => 'közüniñ', 'козюнъни' => 'közüñni', 'койлюде' => 'köylüde',
- 'койлюлер' => 'köylüler', 'койлюлерде' => 'köylülerde', 'койлюлерни' => 'köylülerni',
- 'койлюлернинъ' => 'köylülerniñ', 'койлюнинъ' => 'köylüniñ', 'коккозьге' => 'kökközge',
- 'коккозьде' => 'kökközde', 'коккозьдеки' => 'kökközdeki', 'коккозьден' => 'kökközden',
- 'кокюс' => 'köküs', 'кокюси' => 'köküsi', 'кокюсим' => 'köküsim', 'кокюсиме' => 'köküsime',
- 'кокюсинъе' => 'köküsiñe', 'комиссарлар' => 'komissarlar', 'комиссарлары' => 'komissarları',
- 'комитетининъ' => 'komitetiniñ', 'концлагерь' => 'kontslager', 'копьмеди' => 'köpmedi',
- 'копьти' => 'köpti', 'копюр' => 'köpür', 'копюрге' => 'köpürge', 'копюрден' => 'köpürden',
- 'копюри' => 'köpüri', 'копюрнинъ' => 'köpürniñ', 'коридорда' => 'koridorda',
- 'корьсюн' => 'körsün', 'корюв' => 'körüv', 'корюльген' => 'körülgen', 'корюнди' => 'köründi',
- 'корюндинъ' => 'köründiñ', 'корюне' => 'körüne', 'корюнип' => 'körünip',
- 'корюнмеген' => 'körünmegen', 'корюнмеди' => 'körünmedi', 'корюнмедилер' => 'körünmediler',
- 'корюнмей' => 'körünmey', 'корюнмейсинъиз' => 'körünmeysiñiz', 'корюнмекте' => 'körünmekte',
- 'корюнмектелер' => 'körünmekteler', 'корюнъиз' => 'körüñiz', 'корюше' => 'körüşe',
- 'корюшеджекмиз' => 'körüşecekmiz', 'корюшим' => 'körüşim', 'корюшип' => 'körüşip',
- 'корюширмиз' => 'körüşirmiz', 'корюшкен' => 'körüşken', 'корюшкенде' => 'körüşkende',
- 'корюшмеге' => 'körüşmege', 'корюшмегенимиз' => 'körüşmegenimiz', 'корюштик' => 'körüştik',
- 'корюштим' => 'körüştim', 'корюшюв' => 'körüşüv', 'корюшювде' => 'körüşüvde',
- 'корюшювден' => 'körüşüvden', 'корюшюви' => 'körüşüvi', 'корюшювимден' => 'körüşüvimden',
- 'корюшювимизге' => 'körüşüvimizge', 'корюшювимизден' => 'körüşüvimizden',
- 'костюми' => 'kostümi', 'кузю' => 'küzü', 'кулькюден' => 'külküden', 'кулькюнинъ' => 'külküniñ',
- 'кулькюсининъ' => 'külküsiniñ', 'кулю' => 'külü', 'кулюмсиреген' => 'külümsiregen',
- 'кулюмсиреди' => 'külümsiredi', 'кулюмсиредим' => 'külümsiredim', 'кулюмсирей' => 'külümsirey',
- 'кулюмсирейим' => 'külümsireyim', 'кулюмсиреп' => 'külümsirep', 'кулюни' => 'külüni',
- 'кулюнчли' => 'külünçli', 'кулюшинде' => 'külüşinde', 'кулюштилер' => 'külüştiler',
- 'кумюш' => 'kümüş', 'куньдюз' => 'kündüz', 'куньдюзлери' => 'kündüzleri', 'куньлюк' => 'künlük',
- 'куню' => 'künü', 'кунюмде' => 'künümde', 'кунюнде' => 'kününde', 'кунюндеми' => 'künündemi',
- 'кунюнъ' => 'künüñ', 'курькчю' => 'kürkçü', 'курьсю' => 'kürsü', 'курьсюге' => 'kürsüge',
- 'курьсюлер' => 'kürsüler', 'курючтен' => 'kürüçten', 'кутюклерни' => 'kütüklerni',
- 'кутюкли' => 'kütükli', 'кучьлю' => 'küçlü', 'кучьлюклер' => 'küçlükler',
- 'кучьсюнмезсинъ' => 'küçsünmezsiñ', 'кучюджик' => 'küçücik', 'кучюк' => 'küçük',
- 'кучюм' => 'küçüm', 'кучюмле' => 'küçümle', 'кучюнден' => 'küçünden', 'кучюни' => 'küçüni',
- 'къаарьлене' => 'qaarlene', 'къаарьли' => 'qaarli', 'къальбим' => 'qalbim',
- 'къальбимни' => 'qalbimni', 'къальбинде' => 'qalbinde', 'къальпли' => 'qalpli',
- 'къальптен' => 'qalpten', 'къалюбелядан' => 'qalübelâdan', 'къулюбенъде' => 'qulübeñde',
- 'лёман' => 'löman', 'львованынъ' => 'lvovanıñ', 'лютфи' => 'lütfi', 'лютфиге' => 'lütfige',
- 'лютфини' => 'lütfini', 'мазюн' => 'mazün', 'малюм' => 'malüm', 'малюмат' => 'malümat',
- 'махлюкъаттан' => 'mahlüqattan', 'махлюкътан' => 'mahlüqtan', 'махульдюрге' => 'mahuldürge',
- 'махульдюрде' => 'mahuldürde', 'махульдюрдеки' => 'mahuldürdeki',
- 'махульдюрден' => 'mahuldürden', 'махульдюрли' => 'mahuldürli',
- 'махульдюрлилер' => 'mahuldürliler', 'махульдюрлилермиз' => 'mahuldürlilermiz',
- 'махульдюрми' => 'mahuldürmi', 'махульдюрни' => 'mahuldürni', 'мевджут' => 'mevcut',
- 'мезкюр' => 'mezkür', 'мектюп' => 'mektüp', 'мектюпни' => 'mektüpni', 'мектюпте' => 'mektüpte',
- 'мелитопольге' => 'melitopolge', 'мемнюн' => 'memnün', 'мемнюниетле' => 'memnüniyetle',
- 'мемнюним' => 'memnünim', 'мемнюнмиз' => 'memnünmiz', 'менсюп' => 'mensüp',
- 'мешгъульмиз' => 'meşğulmiz', 'мулькюни' => 'mülküni', 'мумкюн' => 'mümkün',
- 'мумкюнми' => 'mümkünmi', 'мусульманлар' => 'musulmanlar', 'мусульманлармы' => 'musulmanlarmı',
- 'мухкемлендирюв' => 'mühkemlendirüv', 'мушкюль' => 'müşkül', 'ничюн' => 'niçün',
- 'ничюндир' => 'niçündir', 'нумюнеси' => 'nümünesi', 'огю' => 'ögü', 'огюз' => 'ögüz',
- 'огюмде' => 'ögümde', 'огюмдеки' => 'ögümdeki', 'огюме' => 'ögüme', 'огюмизге' => 'ögümizge',
- 'огюмизде' => 'ögümizde', 'огюмиздеки' => 'ögümizdeki', 'огюмни' => 'ögümni',
- 'огюнде' => 'ögünde', 'огюндеки' => 'ögündeki', 'огюндекиси' => 'ögündekisi',
- 'огюнден' => 'ögünden', 'огюне' => 'ögüne', 'огюнъизде' => 'ögüñizde', 'огютини' => 'ögütini',
- 'огютлерини' => 'ögütlerini', 'озю' => 'özü', 'озюм' => 'özüm', 'озюмден' => 'özümden',
- 'озюме' => 'özüme', 'озюмизни' => 'özümizni', 'озюмизнинъ' => 'özümizniñ',
- 'озюмизнинъки' => 'özümizniñki', 'озюмнен' => 'özümnen', 'озюмни' => 'özümni',
- 'озюмнинъ' => 'özümniñ', 'озюнде' => 'özünde', 'озюнден' => 'özünden', 'озюне' => 'özüne',
- 'озюнен' => 'özünen', 'озюни' => 'özüni', 'озюнинъ' => 'özüniñ', 'озюнинъкими' => 'özüniñkimi',
- 'озюнъ' => 'özüñ', 'озюнъе' => 'özüñe', 'озюнъиз' => 'özüñiz', 'озюнъиздеки' => 'özüñizdeki',
- 'озюнъни' => 'özüñni', 'оксюз' => 'öksüz', 'окюндим' => 'ökündim', 'ольдюрип' => 'öldürip',
- 'ольдюрмек' => 'öldürmek', 'ольдюрювде' => 'öldürüvde', 'ольчюде' => 'ölçüde', 'олюм' => 'ölüm',
- 'олюмден' => 'ölümden', 'олюмлер' => 'ölümler', 'омюр' => 'ömür', 'омюрге' => 'ömürge',
- 'омюри' => 'ömüri', 'опькеленюв' => 'öpkelenüv', 'орьтилюви' => 'örtilüvi', 'орьтюли' => 'örtüli',
- 'орюли' => 'örüli', 'орюлип' => 'örülip', 'осюв' => 'ösüv', 'осюмлик' => 'ösümlik',
- 'отькерювни' => 'ötkerüvni', 'отькюр' => 'ötkür', 'офицери' => 'ofitseri',
- 'офицерим' => 'ofitserim', 'офицерлер' => 'ofitserler', 'пальтосыны' => 'paltosını',
- 'пальтосынынъ' => 'paltosınıñ', 'пекинюв' => 'pekinüv', 'пекитювнинъ' => 'pekitüvniñ',
- 'пиширюв' => 'pişirüv', 'повидло' => 'povidlo', 'полис' => 'polis', 'полициясы' => 'politsiyası',
- 'помещик' => 'pomeşçik', 'потюк' => 'potük', 'потюклеринен' => 'potüklerinen',
- 'пулемёт' => 'pülemöt', 'пулемётларны' => 'pülemötlarnı', 'режиссёр' => 'rejissör',
- 'ролюнде' => 'rolünde', 'севастопольнинъ' => 'sevastopolniñ', 'сёгди' => 'sögdi', 'сёз' => 'söz',
- 'сёзлер' => 'sözler', 'сёзлери' => 'sözleri', 'сёзлерим' => 'sözlerim',
- 'сёзлеримден' => 'sözlerimden', 'сёзлериме' => 'sözlerime', 'сёзлеримни' => 'sözlerimni',
- 'сёзлеримнинъ' => 'sözlerimniñ', 'сёзлеринде' => 'sözlerinde', 'сёзлерине' => 'sözlerine',
- 'сёзлерини' => 'sözlerini', 'сёзлерининъ' => 'sözleriniñ', 'сёзлеринъиз' => 'sözleriñiz',
- 'сёзлеринъизни' => 'sözleriñizni', 'сёзлернен' => 'sözlernen', 'сёзлерни' => 'sözlerni',
- 'сёзлернинъ' => 'sözlerniñ', 'сёзнен' => 'söznen', 'сёзни' => 'sözni', 'сёзчиклер' => 'sözçikler',
- 'сёзчиклерден' => 'sözçiklerden', 'сёзю' => 'sözü', 'сёзюмен' => 'sözümen',
- 'сёзюмнинъ' => 'sözümniñ', 'сёзюне' => 'sözüne', 'сёзюни' => 'sözüni', 'сёзюнинъ' => 'sözüniñ',
- 'сёйле' => 'söyle', 'сёйлегенде' => 'söylegende', 'сёйлегенлеринден' => 'söylegenlerinden',
- 'сёйледи' => 'söyledi', 'сёйлей' => 'söyley', 'сёйленди' => 'söylendi',
- 'сёйленмеге' => 'söylenmege', 'сёйленмекте' => 'söylenmekte', 'сёйленъиз' => 'söyleñiz',
- 'сёнген' => 'söngen', 'сёнди' => 'söndi', 'сёндюрди' => 'söndürdi',
- 'сёндюрильген' => 'söndürilgen', 'сёндюрип' => 'söndürip', 'сентябрьнинъ' => 'sentâbrniñ',
- 'сергюзешт' => 'sergüzeşt', 'сергюзештлерни' => 'sergüzeştlerni',
- 'ставропольге' => 'stavropolge', 'сулькевич' => 'sulkeviç', 'сурьат' => 'surat',
- 'суфлёр' => 'suflör', 'сюеги' => 'süyegi', 'сюеклерге' => 'süyeklerge',
- 'сюйрекледи' => 'süyrekledi', 'сюйреле' => 'süyrele', 'сюйрен' => 'süyren',
- 'сюйренге' => 'süyrenge', 'сюйренде' => 'süyrende', 'сюйреп' => 'süyrep', 'сюйрю' => 'süyrü',
- 'сюкюнет' => 'sükünet', 'сюкюнети' => 'süküneti', 'сюкюнетте' => 'sükünette', 'сюкют' => 'süküt',
- 'сюляле' => 'sülâle', 'сюрген' => 'sürgen', 'сюрди' => 'sürdi', 'сюрмеди' => 'sürmedi',
- 'сюрюльмеген' => 'sürülmegen', 'сют' => 'süt', 'тебессюм' => 'tebessüm', 'тёкип' => 'tökip',
- 'тёкти' => 'tökti', 'тёкюльген' => 'tökülgen', 'тёкюльди' => 'töküldi',
- 'тёкюндиси' => 'tökündisi', 'тёле' => 'töle', 'тёледим' => 'töledim', 'телюке' => 'telüke',
- 'телюкели' => 'telükeli', 'тенеффюс' => 'teneffüs', 'тенеффюслер' => 'teneffüsler',
- 'тёпеге' => 'töpege', 'тёпелери' => 'töpeleri', 'тёпелерине' => 'töpelerine',
- 'тёпели' => 'töpeli', 'тёпеси' => 'töpesi', 'тёпесинден' => 'töpesinden',
- 'тёпесини' => 'töpesini', 'тёрге' => 'törge', 'тёрде' => 'törde', 'тёрдеки' => 'tördeki',
- 'тёрюне' => 'törüne', 'тешеббюсим' => 'teşebbüsim', 'тёшегинден' => 'töşeginden',
- 'тёшегине' => 'töşegine', 'тёшек' => 'töşek', 'тешеккюр' => 'teşekkür',
- 'тешеккюрлер' => 'teşekkürler', 'тёшекни' => 'töşekni', 'тёшектен' => 'töşekten',
- 'тёшели' => 'töşeli', 'тёшемек' => 'töşemek', 'тёшеп' => 'töşep', 'теэссюф' => 'teessüf',
- 'тюбю' => 'tübü', 'тюбюнде' => 'tübünde', 'тюбюндеки' => 'tübündeki', 'тюз' => 'tüz',
- 'тюзельгенге' => 'tüzelgenge', 'тюзельтмек' => 'tüzeltmek', 'тюземликлер' => 'tüzemlikler',
- 'тюзетип' => 'tüzetip', 'тюзетирим' => 'tüzetirim', 'тюзеткен' => 'tüzetken',
- 'тюзетмеге' => 'tüzetmege', 'тюзетмесенъ' => 'tüzetmeseñ', 'тюзетти' => 'tüzetti',
- 'тюзетюв' => 'tüzetüv', 'тюкенмез' => 'tükenmez', 'тюкюриктен' => 'tükürikten',
- 'тюкян' => 'tükân', 'тюкяны' => 'tükânı', 'тюкянында' => 'tükânında', 'тюм' => 'tüm',
- 'тюневин' => 'tünevin', 'тюневинки' => 'tünevinki', 'тюпсюз' => 'tüpsüz', 'тюрк' => 'türk',
- 'тюрклернинъ' => 'türklerniñ', 'тюркнинъ' => 'türkniñ', 'тюркче' => 'türkçe', 'тюркю' => 'türkü',
- 'тюркюлерини' => 'türkülerini', 'тюркюнинъ' => 'türküniñ', 'тюрлю' => 'türlü',
- 'тюртип' => 'türtip', 'тюрттинъиз' => 'türttiñiz', 'тютемекте' => 'tütemekte', 'тютюн' => 'tütün',
- 'тютюнджи' => 'tütünci', 'тюфеги' => 'tüfegi', 'тюфегини' => 'tüfegini', 'тюфек' => 'tüfek',
- 'тюфеклеринен' => 'tüfeklerinen', 'тюфеклернен' => 'tüfeklernen', 'тюфеклерни' => 'tüfeklerni',
- 'тюфекнен' => 'tüfeknen', 'тюфексиз' => 'tüfeksiz', 'тюш' => 'tüş', 'тюше' => 'tüşe',
- 'тюшеджек' => 'tüşecek', 'тюшеджексинъми' => 'tüşeceksiñmi', 'тюшем' => 'tüşem',
- 'тюшип' => 'tüşip', 'тюшкен' => 'tüşken', 'тюшкенде' => 'tüşkende', 'тюшкенлер' => 'tüşkenler',
- 'тюшмеге' => 'tüşmege', 'тюшмейим' => 'tüşmeyim', 'тюшмейлер' => 'tüşmeyler',
- 'тюшмек' => 'tüşmek', 'тюшмекте' => 'tüşmekte', 'тюшмеси' => 'tüşmesi', 'тюшсе' => 'tüşse',
- 'тюшти' => 'tüşti', 'тюштик' => 'tüştik', 'тюштилер' => 'tüştiler', 'тюштими' => 'tüştimi',
- 'тюштинъиз' => 'tüştiñiz', 'тюшювден' => 'tüşüvden', 'тюшюджек' => 'tüşücek',
- 'тюшюнген' => 'tüşüngen', 'тюшюнгендже' => 'tüşüngence', 'тюшюндже' => 'tüşünce',
- 'тюшюнджеге' => 'tüşüncege', 'тюшюнджелер' => 'tüşünceler', 'тюшюнджелери' => 'tüşünceleri',
- 'тюшюнджелерим' => 'tüşüncelerim', 'тюшюнджели' => 'tüşünceli', 'тюшюнджеси' => 'tüşüncesi',
- 'тюшюнди' => 'tüşündi', 'тюшюндим' => 'tüşündim', 'тюшюне' => 'tüşüne',
- 'тюшюнелер' => 'tüşüneler', 'тюшюнесинъиз' => 'tüşünesiñiz', 'тюшюнип' => 'tüşünip',
- 'тюшюнмеге' => 'tüşünmege', 'тюшюнмезсинъ' => 'tüşünmezsiñ', 'тюшюнмей' => 'tüşünmey',
- 'тюшюнмемек' => 'tüşünmemek', 'тюшюргенлер' => 'tüşürgenler', 'тюшюрди' => 'tüşürdi',
- 'тюшюрдик' => 'tüşürdik', 'тюшюре' => 'tüşüre', 'тюшюрип' => 'tüşürip', 'тюшюрмек' => 'tüşürmek',
- 'уджюм' => 'ücüm', 'удюр' => 'üdür', 'узюле' => 'üzüle', 'узюлип' => 'üzülip',
- 'узюльгенини' => 'üzülgenini', 'узюльди' => 'üzüldi', 'уйрюлип' => 'üyrülip',
- 'укюмет' => 'ükümet', 'укюмети' => 'ükümeti', 'укюметими' => 'ükümetimi',
- 'укюметимиз' => 'ükümetimiz', 'укюметини' => 'ükümetini', 'укюметининъ' => 'ükümetiniñ',
- 'укюметке' => 'ükümetke', 'укюметкеми' => 'ükümetkemi', 'укюметми' => 'ükümetmi',
- 'укюметнинъ' => 'ükümetniñ', 'укюметтен' => 'ükümetten', 'укюмран' => 'ükümran',
- 'улькюн' => 'ülkün', 'умюдим' => 'ümüdim', 'умют' => 'ümüt', 'умютлери' => 'ümütleri',
- 'умютсизден' => 'ümütsizden', 'усть' => 'üst', 'устьке' => 'üstke', 'устьлеринде' => 'üstlerinde',
- 'устьлериндеки' => 'üstlerindeki', 'устьлерине' => 'üstlerine', 'устьлерини' => 'üstlerini',
- 'устюрткъа' => 'üsturtqa', 'усьнюхаткъа' => 'üsnühatqa', 'усьнюхаты' => 'üsnühatı',
- 'усьтю' => 'üstü', 'усьтюмде' => 'üstümde', 'усьтюмдеки' => 'üstümdeki', 'усьтюме' => 'üstüme',
- 'усьтюнде' => 'üstünde', 'усьтюндеки' => 'üstündeki', 'усьтюндемиз' => 'üstündemiz',
- 'усьтюне' => 'üstüne', 'усьтюни' => 'üstüni', 'усьтюнлик' => 'üstünlik',
- 'усьтюнъизге' => 'üstüñizge', 'утёкунь' => 'ütökün', 'уфюрди' => 'üfürdi', 'учю' => 'üçü',
- 'учюмиз' => 'üçümiz', 'учюн' => 'üçün', 'учюнджи' => 'üçünci', 'учюнджисининъ' => 'üçüncisiniñ',
- 'ушюй' => 'üşüy', 'ушюмез' => 'üşümez', 'ушюмезсинъ' => 'üşümezsiñ',
- 'факультетинде' => 'fakultetinde', 'факультетине' => 'fakultetine',
- 'февральнинъ' => 'fevralniñ', 'харьковдаки' => 'harkovdaki', 'харьковдан' => 'harkovdan',
- 'чёкти' => 'çökti', 'чёкюрли' => 'çökürli', 'чёкюч' => 'çöküç', 'чёллюкке' => 'çöllükke',
- 'чёль' => 'çöl', 'чёльде' => 'çölde', 'чёльмек' => 'çölmek', 'чёткю' => 'çötkü',
- 'чёчамийлер' => 'çöçamiyler', 'чюнки' => 'çünki', 'чюрюди' => 'çürüdi', 'чюрюк' => 'çürük',
- 'шукюр' => 'şükür', 'шукюрлер' => 'şükürler', 'этюв' => 'etüv', 'этювден' => 'etüvden',
- 'этюви' => 'etüvi', 'этюдлар' => 'etüdlar', 'юзден' => 'yüzden', 'юзлеп' => 'yüzlep',
- 'юзлерини' => 'yüzlerini', 'юзлернен' => 'yüzlernen', 'юзлюги' => 'yüzlügi',
- 'юзлюкке' => 'yüzlükke', 'юзю' => 'yüzü', 'юзюм' => 'yüzüm', 'юзюме' => 'yüzüme',
- 'юзюмен' => 'yüzümen', 'юзюмни' => 'yüzümni', 'юзюнде' => 'yüzünde', 'юзюни' => 'yüzüni',
- 'юзюнинъ' => 'yüzüniñ', 'юзюнъ' => 'yüzüñ', 'юзюнъизге' => 'yüzüñizge', 'юклю' => 'yüklü',
- 'юксельтюв' => 'yükseltüv', 'юньлю' => 'yünlü', 'юньлюдже' => 'yünlüce',
- 'юртсеверлик' => 'yurtseverlik', 'юртюде' => 'yürtüde', 'юрьтю' => 'yürtü',
- 'юрьтюге' => 'yürtüge', 'юрьтюнинъ' => 'yürtüniñ', 'юрюльсе' => 'yürülse', 'юрюнъиз' => 'yürüñiz',
- 'юрюш' => 'yürüş', 'юрюши' => 'yürüşi', 'юрюшим' => 'yürüşim', 'юрюшини' => 'yürüşini',
- 'юрюшнен' => 'yürüşnen', 'юрюшни' => 'yürüşni',
];
- # map Cyrillic to Latin and back, whole word match only
+ # map Cyrillic to Latin and back, simple string match only (no regex)
# no variants: map exactly as is
- # items with capture group refs (e.g., $1) are only mapped from the
- # regex to the reference
private $exactCaseMappings = [
# аббревиатуры
# abbreviations
- 'ОБСЕ' => 'OBSE', 'КъМДж' => 'QMC', 'КъАЭ' => 'QAE', 'ГъСМК' => 'ĞSMK', 'ШСДжБ' => 'ŞSCB',
- 'КъМШСДж' => 'QMŞSC', 'КъДМПУ' => 'QDMPU', 'КъМПУ' => 'QMPU', 'КъЮШ' => 'QYŞ', 'ЮШ' => 'YŞ',
+ 'ОБСЕ' => 'OBSE', 'КъМДж' => 'QMC', 'КъДж' => 'QC', 'КъАЭ' => 'QAE', 'ГъСМК' => 'ĞSMK',
+ 'ШСДжБ' => 'ŞSCB', 'КъМШСДж' => 'QMŞSC', 'КъАССР' => 'QASSR', 'КъДМПУ' => 'QDMPU',
+ 'КъМПУ' => 'QMPU',
];
# map Cyrillic to Latin and back, match end of word
# originally C2L
'иаль' => 'ial', 'нуль' => 'nul', 'кой' => 'köy', 'койнинъ' => 'köyniñ', 'койни' => 'köyni',
'койге' => 'köyge', 'койде' => 'köyde', 'койдеки' => 'köydeki', 'койден' => 'köyden',
- 'козь' => 'köz',
+ 'козь' => 'köz', '-юнджи' => '-ünci', '-юнджиде' => '-üncide', '-юнджиден' => '-ünciden',
# originally L2C, here swapped
- 'етсин' => 'etsin',
+ 'етсин' => 'etsin', 'льная' => 'lnaya', 'льное' => 'lnoye', 'льный' => 'lnıy', 'льний' => 'lniy',
+ 'льская' => 'lskaya', 'льский' => 'lskiy', 'льское' => 'lskoye', 'ополь' => 'opol',
+ 'щее' => 'şçeye', 'щий' => 'şçiy', 'щая' => 'şçaya', 'цепс' => 'tseps',
];
'буюк([^ъ])' => 'büyük$1', 'бую([гдйлмнпрстчшc])(и)' => 'büyü$1$2',
'буют([^ыа])' => 'büyüt$1', 'джонк([^ъ])' => 'cönk$1', 'коюм' => 'köyüm', 'коюнъ' => 'köyüñ',
'коюн([ди])' => 'köyün$1', 'куе' => 'küye', 'куркке' => 'kürkke', 'куркни' => 'kürkni',
- 'куркте' => 'kürkte', 'куркчи' => 'kürkçi', 'куркчю' => 'kürkçü',
+ 'куркте' => 'kürkte', 'куркчю' => 'kürkçü', 'кою' => 'köyü',
+ 'жизнь' => 'jizn',
# арабизмы на муи- муэ- / Arabic муи- муэ-
'му([иэИЭ])' => 'mü$1',
# originally L2C, here swapped
- 'итъаль' => 'ital',
'роль$1' => 'rol([^ü])',
- 'усть$1' => 'üst([knt])',
+ 'усть$1' => 'üst([^ü])',
+
+ # more prefixes
+ 'ком-кок' => 'köm-kök',
];
# относятся ко всему слову #
# whole words #
############################
- '/\b([34])(\-)юнджи\b/u' => '$1$2ünci',
- '/\b([34])(\-)ЮНДЖИ\b/u' => '$1$2ÜNCİ',
+
+ // TODO: refactor upper/lower/first capital whole words without
+ // regexes into simpler list
+
+ '/\bКъЮШ\b/u' => 'QYŞ',
+ '/\bЮШ\b/u' => 'YŞ',
+
+ '/\bкок\b/u' => 'kök',
+ '/\bКок\b/u' => 'Kök',
+ '/\bКОК\b/u' => 'KÖK',
+ '/\bком-кок\b/u' => 'köm-kök',
+ '/\bКом-кок\b/u' => 'Köm-kök',
+ '/\bКОМ-КОК\b/u' => 'KÖM-KÖK',
+
+ '/\bкоп\b/u' => 'köp',
+ '/\bКоп\b/u' => 'Köp',
+ '/\bКОП\b/u' => 'KÖP',
+
+ '/\bкурк\b/u' => 'kürk',
+ '/\bКурк\b/u' => 'Kürk',
+ '/\bКУРК\b/u' => 'KÜRK',
+
+ '/\bог\b/u' => 'ög',
+ '/\bОг\b/u' => 'Ög',
+ '/\bОГ\b/u' => 'ÖG',
+
+ '/\bюрип\b/u' => 'yürip',
+ '/\bЮрип\b/u' => 'Yürip',
+ '/\bЮРИП\b/u' => 'YÜRİP',
+
+ '/\bюз\b/u' => 'yüz',
+ '/\bЮз\b/u' => 'Yüz',
+ '/\bЮЗ\b/u' => 'YÜZ',
+
+ '/\bюк\b/u' => 'yük',
+ '/\bЮк\b/u' => 'Yük',
+ '/\bЮК\b/u' => 'YÜK',
+
+ '/\bбуюп\b/u' => 'büyüp',
+ '/\bБуюп\b/u' => 'Büyüp',
+ '/\bБУЮП\b/u' => 'BÜYÜP',
+
+ '/\bбуюк\b/u' => 'büyük',
+ '/\bБуюк\b/u' => 'Büyük',
+ '/\bБУЮК\b/u' => 'BÜYÜK',
+
+ '/\bджонк\b/u' => 'cönk',
+ '/\bДжонк\b/u' => 'Cönk',
+ '/\bДЖОНК\b/u' => 'CÖNK',
+ '/\bджонкю\b/u' => 'cönkü',
+ '/\bДжонкю\b/u' => 'Cönkü',
+ '/\bДЖОНКЮ\b/u' => 'CÖNKÜ',
+
+ '/\bустке\b/u' => 'üstke',
+ '/\bУстке\b/u' => 'Üstke',
+ '/\bУСТКЕ\b/u' => 'ÜSTKE',
+ '/\bустте\b/u' => 'üstte',
+ '/\bУстте\b/u' => 'Üstte',
+ '/\bУСТТЕ\b/u' => 'ÜSTTE',
+ '/\bусттен\b/u' => 'üstten',
+ '/\bУсттен\b/u' => 'Üstten',
+ '/\bУСТТЕН\b/u' => 'ÜSTTEN',
# отдельно стоящие Ё и Я
# stand-alone Ё and Я
'/\bКъЮШн/u' => 'QYŞn',
'/\bЮШн/u' => 'YŞn',
+ # need to convert digraphs (гъ, къ, нъ, дж) now to match patterns
+ '/гъ/u' => 'ğ',
+ '/Г[ъЪ]/u' => 'Ğ',
+ '/къ/u' => 'q',
+ '/К[ъЪ]/u' => 'Q',
+ '/нъ/u' => 'ñ',
+ '/Н[ъЪ]/u' => 'Ñ',
+ '/дж/u' => 'c',
+ '/Д[жЖ]/u' => 'C',
+
# о => ö
'/\b(['.Crh::C_M_CONS.'])о(['.Crh::C_CONS.'])(['.Crh::C_CONS.'])([еиэюьü])/u' => '$1ö$2$3$4',
'/\bо(['.Crh::C_CONS.'])(['.Crh::C_CONS.'])([еиэюьü])/u' => 'ö$1$2$3',
];
$this->Latn2CyrlRegexes = [
+
+ // TODO: refactor upper/lower/first capital whole words without
+ // regexes into simpler list
+
+ '/\ban\b/u' => 'ань',
+ '/\bAn\b/u' => 'Ань',
+ '/\bAN\b/u' => 'АНЬ',
+ '/\bange\b/u' => 'аньге',
+ '/\bAnge\b/u' => 'Аньге',
+ '/\bANGE\b/u' => 'АНЬГЕ',
+ '/\bande\b/u' => 'аньде',
+ '/\bAnde\b/u' => 'Аньде',
+ '/\bANDE\b/u' => 'АНЬДЕ',
+ '/\banki\b/u' => 'аньки',
+ '/\bAnki\b/u' => 'Аньки',
+ '/\bANKİ\b/u' => 'АНЬКИ',
+ '/\bderal\b/u' => 'деръал',
+ '/\bDeral\b/u' => 'Деръал',
+ '/\bDERAL\b/u' => 'ДЕРЪАЛ',
+ '/\bkör\b/u' => 'кёр',
+ '/\bKör\b/u' => 'Кёр',
+ '/\bKÖR\b/u' => 'КЁР',
+ '/\bmer\b/u' => 'мэр',
+ '/\bMer\b/u' => 'Мэр',
+ '/\bMER\b/u' => 'МЭР',
+
+ '/\bджонк/u' => 'cönk',
+ '/\bДжонк/u' => 'Cönk',
+ '/\bДЖОНК/u' => 'CÖNK',
+
+ '/\bкуркчи/u' => 'kürkçi',
+ '/\bКуркчи/u' => 'Kürkçi',
+ '/\bКУРКЧИ/u' => 'KÜRKÇI',
+
# буква Ё - первый заход
# расставляем Ь после согласных
- '/^([yY])ö(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|$)/u' => '$1ö$2ь$3',
- '/^([yY])Ö(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|$)/u' => '$1Ö$2Ь$3',
- '/^AQŞ(['.Crh::WORD_ENDS.'ngd])/u' => 'АКъШ$1',
+ '/\b([yY])ö(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|\b)/u' => '$1ö$2ь$3',
+ '/\b([yY])Ö(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|\b)/u' => '$1Ö$2Ь$3',
+ '/\bAQŞ([^AEI]|\b)/u' => 'АКъШ$1',
# буква Ю - первый заход
# расставляем Ь после согласных
- '/^([yY])ü(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|$)/u' => '$1ü$2ь$3',
- '/^([yY])Ü(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|$)/u' => '$1Ü$2Ь$3',
+ '/\b([yY])ü(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|\b)/u' => '$1ü$2ь$3',
+ '/\b([yY])Ü(['.Crh::L_N_CONS.'])([aAuU'.Crh::L_CONS.']|\b)/u' => '$1Ü$2Ь$3',
- '/^([bcgkpşBCGKPŞ])ö(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => '$1ö$2ь$3',
- '/^([bcgkpşBCGKPŞ])Ö(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => '$1Ö$2Ь$3',
- '/^([bcgkpşBCGKPŞ])Ö(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => '$1Ö$2Ь$3',
- '/^([bcgkpşBCGKPŞ])ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => '$1ü$2ь$3',
- '/^([bcgkpşBCGKPŞ])Ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => '$1Ü$2Ь$3',
- '/^([bcgkpşBCGKPŞ])Ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => '$1Ü$2Ь$3',
+ '/\b([bcgkpşBCGKPŞ])ö(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => '$1ö$2ь$3',
+ '/\b([bcgkpşBCGKPŞ])Ö(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => '$1Ö$2Ь$3',
+ '/\b([bcgkpşBCGKPŞ])Ö(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => '$1Ö$2Ь$3',
+ '/\b([bcgkpşBCGKPŞ])ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => '$1ü$2ь$3',
+ '/\b([bcgkpşBCGKPŞ])Ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => '$1Ü$2Ь$3',
+ '/\b([bcgkpşBCGKPŞ])Ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => '$1Ü$2Ь$3',
# ö и ü в начале слова
# случаи, когда нужен Ь
- '/^ö(['.Crh::L_N_CONS.'pP])(['.Crh::L_CONS.']|$)/u' => 'ö$1ь$2',
- '/^Ö(['.Crh::L_N_CONS_LC.'p])(['.Crh::L_CONS.']|$)/u' => 'Ö$1ь$2',
- '/^Ö(['.Crh::L_N_CONS_UC.'P])(['.Crh::L_CONS.']|$)/u' => 'Ö$1Ь$2',
- '/^ü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|$)/u' => 'ü$1ь$2',
- '/^Ü(['.Crh::L_N_CONS_LC.'])(['.Crh::L_CONS.']|$)/u' => 'Ü$1ь$2',
- '/^Ü(['.Crh::L_N_CONS_UC.'])(['.Crh::L_CONS.']|$)/u' => 'Ü$1Ь$2',
-
- '/ts$/u' => 'ц',
- '/şç$/u' => 'щ',
- '/Ş[çÇ]$/u' => 'Щ',
- '/T[sS]$/u' => 'Ц',
+ '/\bö(['.Crh::L_N_CONS.'pP])(['.Crh::L_CONS.']|\b)/u' => 'ö$1ь$2',
+ '/\bÖ(['.Crh::L_N_CONS_LC.'p])(['.Crh::L_CONS.']|\b)/u' => 'Ö$1ь$2',
+ '/\bÖ(['.Crh::L_N_CONS_UC.'P])(['.Crh::L_CONS.']|\b)/u' => 'Ö$1Ь$2',
+ '/\bü(['.Crh::L_N_CONS.'])(['.Crh::L_CONS.']|\b)/u' => 'ü$1ь$2',
+ '/\bÜ(['.Crh::L_N_CONS_LC.'])(['.Crh::L_CONS.']|\b)/u' => 'Ü$1ь$2',
+ '/\bÜ(['.Crh::L_N_CONS_UC.'])(['.Crh::L_CONS.']|\b)/u' => 'Ü$1Ь$2',
+
+ '/ts\b/u' => 'ц',
+ '/şç\b/u' => 'щ',
+ '/Ş[çÇ]\b/u' => 'Щ',
+ '/T[sS]\b/u' => 'Ц',
# Ь после Л
# add Ь after Л
- '/(['.Crh::L_F.'])l(['.Crh::L_CONS_LC.']|$)/u' => '$1ль$2',
- '/(['.Crh::L_F_UC.'])L(['.Crh::L_CONS.']|$)/u' => '$1ЛЬ$2',
+ '/(['.Crh::L_F.'])l(['.Crh::L_CONS_LC.']|\b)/u' => '$1ль$2',
+ '/(['.Crh::L_F_UC.'])L(['.Crh::L_CONS.']|\b)/u' => '$1ЛЬ$2',
+
+ '/etsin\b/u' => 'етсин',
+ '/Etsin\b/u' => 'Етсин',
+ '/ETSİN\b/u' => 'ЕТСИН',
# относятся к началу слова
- '/^ts/u' => 'ц',
- '/^T[sS]/u' => 'Ц',
+ '/\bts/u' => 'ц',
+ '/\bT[sS]/u' => 'Ц',
- '/^şç/u' => 'щ',
- '/^Ş[çÇ]/u' => 'Щ',
+ '/\bşç/u' => 'щ',
+ '/\bŞ[çÇ]/u' => 'Щ',
# Э
- '/(^|['.Crh::L_VOW.'аеэяАЕЭЯ])e/u' => '$1э',
- '/(^|['.Crh::L_VOW_UC.'АЕЭЯ])E/u' => '$1Э',
+ '/(\b|['.Crh::L_VOW.'аеэяАЕЭЯ])e/u' => '$1э',
+ '/(\b|['.Crh::L_VOW_UC.'АЕЭЯ])E/u' => '$1Э',
- '/^(['.Crh::L_M_CONS.'])ö/u' => '$1о',
- '/^(['.Crh::L_M_CONS.'])Ö/u' => '$1О',
- '/^(['.Crh::L_M_CONS.'])ü/u' => '$1у',
- '/^(['.Crh::L_M_CONS.'])Ü/u' => '$1У',
+ '/\b(['.Crh::L_M_CONS.'])ö/u' => '$1о',
+ '/\b(['.Crh::L_M_CONS.'])Ö/u' => '$1О',
+ '/\b(['.Crh::L_M_CONS.'])ü/u' => '$1у',
+ '/\b(['.Crh::L_M_CONS.'])Ü/u' => '$1У',
- '/^ö/u' => 'о',
- '/^Ö/u' => 'О',
- '/^ü/u' => 'у',
- '/^Ü/u' => 'У',
+ '/\bö/u' => 'о',
+ '/\bÖ/u' => 'О',
+ '/\bü/u' => 'у',
+ '/\bÜ/u' => 'У',
# некоторые исключения
# some exceptions
'/[ьЬ]([aA])/u' => '$1',
# дж
- '/C(['.Crh::L_UC.Crh::C_UC.'Ъ])/u' => 'ДЖ$1',
+ '/C(['.Crh::L_UC.Crh::C_UC.'АЕЁЙОУЭЮЯ])/u' => 'ДЖ$1',
+ '/(['.Crh::L_UC.Crh::C_UC.'АЕЁЙОУЭЮЯ])C/u' => '$1ДЖ',
# гъ, къ, нъ
- # гъ, къ, нъ
- '/Ğ(['.Crh::L_UC.Crh::C_UC.'Ъ])/u' => 'ГЪ$1',
- '/Q(['.Crh::L_UC.Crh::C_UC.'Ъ])/u' => 'КЪ$1',
- '/Ñ(['.Crh::L_UC.Crh::C_UC.'Ъ])/u' => 'НЪ$1',
+ '/Ğ(['.Crh::L_UC.Crh::C_UC.'])/u' => 'ГЪ$1',
+ '/(['.Crh::L_UC.Crh::C_UC.'Ъ])Ğ/u' => '$1ГЪ',
+
+ '/Q(['.Crh::L_UC.Crh::C_UC.'])/u' => 'КЪ$1',
+ '/(['.Crh::L_UC.Crh::C_UC.'Ъ])Q/u' => '$1КЪ',
+
+ '/Ñ(['.Crh::L_UC.Crh::C_UC.'])/u' => 'НЪ$1',
+ '/(['.Crh::L_UC.Crh::C_UC.'Ъ])Ñ/u' => '$1НЪ',
];
}
public static $names = [
'aa' => 'Qafár af', # Afar
'ab' => 'Аҧсшәа', # Abkhaz
+ 'abs' => 'bahasa ambon', # Ambonese Malay, T193566
'ace' => 'Acèh', # Aceh
'ady' => 'адыгабзэ', # Adyghe
'ady-cyrl' => 'адыгабзэ', # Adyghe
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "Anok kutai jang",
+ "Bonaditya"
+ ]
+ },
+ "tog-oldsig": "Ale pung tanda tangan yang su ada:",
+ "tog-fancysig": "Biking ale pung tanda tangan tu akang jadi teks wiki (seng parlu pranala otomatis lai)",
+ "tog-uselivepreview": "Kas lia pralia deng seng kas muat kintal ulang",
+ "tog-forceeditsummary": "Kas inga beta kal parobahan pung kontak ringkasan mase kosong",
+ "tog-watchlisthideown": "Jang kas lia beta pung parobahan dalang daftar pantou",
+ "tog-watchlisthidebots": "Jang kas lia bot pung parobahan dia da biking dalang daftar pantou",
+ "tog-watchlisthideminor": "Jang kas lia parobahan yang kacil-kacil dalang daftar pantou",
+ "tog-watchlisthideliu": "Jang kas lia pangguna yang su maso log pung parobahan dalang daftar pantou",
+ "tog-watchlisthideanons": "Jang kas lia pangguna seng jalas pung parobahan dalang daftar pantou",
+ "tog-watchlisthidepatrolled": "Jas kas lia parobahan yang su dapa patroli dalang daftar pantou",
+ "tog-watchlisthidecategorization": "Jang kas lia kintal pung kategorisasi",
+ "tog-ccmeonemails": "TOlong kiring beta salinan yang beta da kiring par orang laeng",
+ "tog-diffonly": "Jang kas lia dalang kintal di bawah parobahan yang beda-beda jua",
+ "tog-showhiddencats": "Kas lia kategori tasambunyi",
+ "sunday": "Dominggu/Minggu",
+ "monday": "Senin",
+ "tuesday": "Salasa",
+ "wednesday": "Rabu",
+ "thursday": "Kamis",
+ "friday": "Jumat",
+ "saturday": "Sabtu",
+ "sun": "Min",
+ "mon": "Sen",
+ "tue": "Sal",
+ "wed": "Rab",
+ "thu": "Kam",
+ "fri": "Jum",
+ "sat": "Sab",
+ "january": "Januari",
+ "february": "Pebuari",
+ "march": "Maret",
+ "april": "April",
+ "may_long": "Mey",
+ "june": "Juni",
+ "july": "Juli",
+ "august": "Agustus",
+ "september": "September",
+ "october": "Oktober",
+ "november": "Nopember",
+ "december": "Desember",
+ "january-gen": "Januari",
+ "february-gen": "Februari",
+ "march-gen": "Maret",
+ "april-gen": "April",
+ "may-gen": "Mei",
+ "june-gen": "Juni",
+ "july-gen": "Juli",
+ "august-gen": "Agustus",
+ "september-gen": "September",
+ "october-gen": "Oktober",
+ "november-gen": "November",
+ "december-gen": "Desember",
+ "jan": "Jan",
+ "feb": "Feb",
+ "mar": "Mar",
+ "apr": "Apr",
+ "may": "Mei",
+ "jun": "Jun",
+ "jul": "Jul",
+ "aug": "Ags",
+ "sep": "Sep",
+ "oct": "Okt",
+ "nov": "Nov",
+ "dec": "Des",
+ "pagecategories": "{{PLURAL:$1lKategori}}",
+ "category_header": "Kintal dalang kategori \"$1\"",
+ "subcategories": "Subkategori",
+ "category-media-header": "Media dalang kategori \"$1\"",
+ "hidden-categories": "{{PLURAL:$1|Kategori tasambunyi}}",
+ "category-subcat-count": "{{PLURAL:$2|Akang kategori ada punya {{PLURAL:$1|$1 subkategori}} berikut, dar total $2.}}",
+ "category-article-count": "{{PLURAL:$2|Akang kategori ada punya {{PLURAL:$1|$1 kintal}}, dar total $2.}}",
+ "category-file-count": "{{PLURAL:$2|Kategori ini punya {{PLURAL:$1|$1 berkas}} berikut, dar total $2.}}",
+ "broken-file-category": "Kintal deng akang pung gambar ancor",
+ "about": "Tentang",
+ "newwindow": "(buka di jandela baru)",
+ "cancel": "Kas batal",
+ "mytalk": "Basumbang suara",
+ "navigation": "Navigasi",
+ "and": " deng",
+ "namespaces": "Tampa nama",
+ "variants": "Jenis-jenis",
+ "navigation-heading": "Menu kas tentu arah",
+ "returnto": "Kombale ka $1.",
+ "tagline": "Dar {{SITENAME}}",
+ "help": "Pertolongan",
+ "search": "Dapa cari",
+ "searchbutton": "Cari",
+ "searcharticle": "Lanjut",
+ "history": "Sejarah kintal",
+ "history_short": "Versi lama",
+ "printableversion": "Jenis taceta",
+ "permalink": "Pranala permanen",
+ "view": "Lia",
+ "view-foreign": "Lia di $1",
+ "edit": "Perbaiki Akang",
+ "create": "Biking",
+ "create-local": "Kas tamba deskripsi lokal",
+ "newpage": "Kintal baru",
+ "talkpagelinktext": "bicara",
+ "specialpage": "Kintal spesial",
+ "personaltools": "Alat-alat sandiri",
+ "talk": "Pambicaraan",
+ "views": "Tampilan",
+ "toolbox": "Alat",
+ "tool-link-userrights": "Simpang kalopmpok {{GENDER:$1|pangguna}}",
+ "tool-link-userrights-readonly": "Lia kalompok {{GENDER:$1|pangguna}}",
+ "tool-link-emailuser": "Kiring pasang ka akang {{GENDER:$1|pangguna}}",
+ "imagepage": "Lia berkas pung kintal",
+ "mediawikipage": "Lia sistem pung kintal pasang",
+ "templatepage": "Lia kintal tamplet",
+ "viewhelppage": "Lia bantuan pung kintal",
+ "categorypage": "Lia kategori pung kintal",
+ "viewtalkpage": "Lia kintal par basumbang suara",
+ "otherlanguages": "Dalang bahasa laeng",
+ "redirectedfrom": "(Dapa pindah dar $1)",
+ "redirectpagesub": "kintal voor pengalihan",
+ "redirectto": "Pi ka:",
+ "lastmodifiedat": "Kintal akang dong ubah terakhir tanggal $1, jam $2.",
+ "viewcount": "Akang kintal su diakses sabanya {{PLURAL:$1|$1 kali}}.<br />",
+ "protectedpage": "Kintal yang dapa lindung",
+ "jumpto": "Balumpa ka:",
+ "jumptonavigation": "penentu arah",
+ "jumptosearch": "cari",
+ "view-pool-error": "Aoe, mohon maaf jua e, server dong sakaran ada sibuk. Talalu banya pangguna yang coba mo balia akang kintal. Tunggu sadiki do sabalong Ale coba akses akang kintal sakali lai.\n\n$1",
+ "generic-pool-error": "Aoe, mohon maaf jua e, server dong sakaran ada sibuk. Talalu banya pangguna yang coba mo balia akang sumber. Tunggu sadiki do sabalong Ale coba akses akang kintal sakali lai.\n\n$1",
+ "pool-timeout": "Waktu su talewat par batunggu konci",
+ "aboutsite": "Tentang {{SITENAME}}",
+ "aboutpage": "Project:Tentang",
+ "copyrightpage": "{{ns:project}}:Hak cipta",
+ "currentevents": "Kajadiang sakarang",
+ "currentevents-url": "Project:Kajadiang sakarang",
+ "disclaimers": "Panyangkalan",
+ "disclaimerpage": "Project:Panyangkalan umum",
+ "edithelp": "Bantuan mo robah",
+ "mainpage": "Kintal Muka",
+ "mainpage-description": "Kintal muka",
+ "portal": "Portal kalompok",
+ "portal-url": "Project:Portal kalompok",
+ "privacy": "Urusan sandiri",
+ "privacypage": "Project:Kebijakan privasi",
+ "retrievedfrom": "Dapa dar \"$1\"",
+ "newmessageslinkplural": "{{PLURAL:$1|pasang baru|pasang baru}}",
+ "newmessagesdifflinkplural": "{{PLURAL:$1|parobahan|999=parobahan}} terakhir",
+ "editsection": "kas ubah",
+ "editold": "kas ubah",
+ "editlink": "kas ubah",
+ "viewsourcelink": "lia sumber data",
+ "editsectionhint": "Kas ubah bagian: $1",
+ "toc": "Isi dalang",
+ "site-atom-feed": "Atom pung umpan $1",
+ "page-atom-feed": "Umpan Atom \"$1\"",
+ "red-link-title": "$1 (halaman seng ada)",
+ "nstab-main": "Kintal",
+ "nstab-user": "Pangguna",
+ "nstab-special": "Kintal spesial",
+ "nstab-project": "Proyek pung kintal",
+ "nstab-image": "Berkas",
+ "nstab-mediawiki": "Pasang",
+ "nstab-template": "Templat",
+ "nstab-category": "Kategori",
+ "mainpage-nstab": "Kintal muka",
+ "nosuchspecialpage": "Seng ada kintal yang spesial bagitu",
+ "nospecialpagetext": "<strong>Ale mo kintal istimewa, akang seng sah.</strong>\n\nDaftar kintal istimewa, akang sah, ale dong bole lia di [[Special:SpecialPages|{{int:specialpages}}]].",
+ "badtitle": "Judul seng bae",
+ "badtitletext": "Kintal pung judul yang ale dong minta seng sah, seng ada, ka judul lintas bahasa deng lintas wiki salah sambung",
+ "viewsource": "lia sumber data",
+ "viewsource-title": "Lia sumber par $1",
+ "viewsourcetext": "Ale dapa lia ka salin sumber dar akang kintal",
+ "userlogin-yourname": "Nama pangguna",
+ "userlogin-yourname-ph": "Kas maso ale pung nama pangguna",
+ "userlogin-yourpassword": "Kata pengaman",
+ "userlogin-yourpassword-ph": "Kas mato ale pung kata pengaman",
+ "createacct-yourpassword-ph": "Kas maso kata pengaman",
+ "createacct-yourpasswordagain": "Kas konfirm ale pung kata pengaman",
+ "createacct-yourpasswordagain-ph": "Kas maso sakali lai ale pung kata pengaman",
+ "userlogin-remembermypassword": "Biarkan beta tetap maso jua",
+ "login": "Maso dalang Log",
+ "userlogin-noaccount": "Seng ada akun?",
+ "userlogin-joinproject": "Baiko {{SITENAME}}",
+ "createaccount": "Biking akun",
+ "userlogin-resetpassword-link": "Seng inga ale pung kata sandi ka?",
+ "userlogin-helplink2": "Bantuan par maso log",
+ "createacct-emailoptional": "Email pung alamat (kal bisa, isi)",
+ "createacct-email-ph": "Kas maso ale pung email",
+ "createacct-submit": "Biking ale pung akun",
+ "createacct-benefit-heading": "{{SITENAME}} dibiking dar orang-orang macang ale dong.",
+ "createacct-benefit-body1": "{{PLURAL:$1|parobahan}}",
+ "createacct-benefit-body2": "{{PLURAL:$1|halaman}}",
+ "createacct-benefit-body3": "{{PLURAL:$1|kontributor}} terakhir",
+ "loginlanguagelabel": "Bahasa: $1",
+ "pt-login": "Maso dalang Log",
+ "pt-login-button": "Maso dalang Log",
+ "pt-createaccount": "Biking Akun",
+ "pt-userlogout": "Kaluar log",
+ "passwordreset": "Robah kata pengaman",
+ "bold_sample": "Teks akang bakal dong cetak tabal",
+ "bold_tip": "Teks tabal",
+ "italic_sample": "Teks akang dong cetak miring",
+ "italic_tip": "Teks miring",
+ "link_sample": "Pranala pung judul",
+ "link_tip": "Pranal internal",
+ "extlink_sample": "http://www.example.com pranala pung judul",
+ "extlink_tip": "Pranala luar (jang lupa awalan http:// )",
+ "headline_sample": "Teks judul",
+ "nowiki_sample": "Kas maso teks yang seng mau dapa format ka sini",
+ "nowiki_tip": "Jang talalu pikir wiki pung format",
+ "image_tip": "Kas tambah berkas",
+ "media_tip": "Pranala ka berkas",
+ "sig_tip": "Ale pung tanda tangan deng tanda waktu",
+ "hr_tip": "Garis horizontal",
+ "summary": "Ringkasan",
+ "minoredit": "Akang dapa robah sadiki sa",
+ "watchthis": "Pantou akang kintal",
+ "savearticle": "Simpang kintal",
+ "preview": "Pralia",
+ "showpreview": "Lia tayang lama",
+ "showdiff": "Lia parobahan",
+ "loginreqlink": "maso dalang log",
+ "noarticletext": "Sakarang seng ada tulisan di akang kintal.\nAle dapa [[Special:Search/{{PAGENAME}}| cari ini kintal pung judul]] di kintal akang, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cari log taika], kal seng [{{fullurl:{{FULLPAGENAME}}|action=edit}} biking kintal akang]</span>.",
+ "userpage-userdoesnotexist-view": "Pangguna \"$1\" akang seng tadaftar.",
+ "editing": "Marobah $1",
+ "creating": "Biking $!",
+ "editingsection": "Ada marobah $1 (bagian)",
+ "templatesused": "{{PLURAL:$1|Templat|Templat}} yang dipake dalang akang kintal:",
+ "template-protected": "(dapa lindung)",
+ "template-semiprotected": "(dilindungi sapanggal)",
+ "hiddencategories": "Akang kintal, anggota dar {{PLURAL:$1|1 kategori tasambunyi|$1 kategori tasambunyi}}:",
+ "permissionserrorstext-withaction": "Ale seng punya hak par akses $2, tagal {{PLURAL:$1|alasan|alasan}} akang:",
+ "moveddeleted-notice": "Akang kintal su dihapus.\nLog voor hapus, perlindungan, deng kas pindah dar kintal yang ada di bawah par referensi.",
+ "content-model-wikitext": "teks wiki",
+ "viewpagelogs": "Lia akang kintal pung log",
+ "currentrev-asof": "Revisi terakhir di $1",
+ "revisionasof": "Parobahan par $1",
+ "revision-info": "Revisi $1 dar {{GENDER:$6|$2}}$7",
+ "previousrevision": "← Parobahan lama",
+ "nextrevision": "Revisi kamuka →",
+ "currentrevisionlink": "Revisi terakhir",
+ "cur": "skr",
+ "last": "sabalong",
+ "history-fieldset-title": "Cari revisi",
+ "histfirst": "paleng lama",
+ "histlast": "paleng baru",
+ "history-feed-title": "Sejarah revisi",
+ "history-feed-description": "Akang kintal pung sejarah revisi dalang wiki",
+ "history-feed-item-nocomment": "$1 dalang $2",
+ "rev-delundel": "robah akang jadi talia ka seng",
+ "history-title": "Sejarah parobahan dar \"$1\"",
+ "difference-title": "$1: Parobahan pung beda",
+ "lineno": "Baris $1",
+ "compareselectedversions": "Kas banding versi yang su dipilih",
+ "editundo": "kas bale",
+ "diff-multi-sameuser": "({{PLURAL:$1|$1 revisi antara}} dar pangguna yang seng dapa kase lia)",
+ "searchresults": "Hasil bacari",
+ "searchresults-title": "Hasil par cari $1",
+ "prevn": "{{PLURAL:$1|$1}} sabalongnya",
+ "nextn": "{{PLURAL:$1|$1}} kamuka",
+ "nextn-title": "$1 {{PLURAL:$1|hasil|hasil}} kamuka",
+ "shown-title": "Kas lia $1 {{PLURAL:$1|hasil}} tiap kintal",
+ "viewprevnext": "Lia ($1 {{int:pipe-separator}} $2) ($3)",
+ "searchmenu-new": "<strong>Biking kintal \"[[:$1]]\" di akang wiki!</strong> {{PLURAL:$2|0=|Lia lai kintal yang su didapa dar ale su pancari.|Lia lai hasil pancarian yang su dijumpa.}}",
+ "searchprofile-articles": "Kintal dalang",
+ "searchprofile-images": "Multimedia",
+ "searchprofile-everything": "Samua",
+ "searchprofile-advanced": "Lanjutan",
+ "searchprofile-articles-tooltip": "Cari di $1",
+ "searchprofile-images-tooltip": "Pancari berkas",
+ "searchprofile-everything-tooltip": "Cari samua hal (termaso kintal par baku suara)",
+ "searchprofile-advanced-tooltip": "Cari di tampa nama spesial",
+ "search-result-size": "$1 ({{PLURAL:$2|1 kata|$2 kata}})",
+ "search-result-category-size": "{{PLURAL:$1|1 anggota|$1 anggota}} ({{PLURAL:$2|1 subkategori|$2 subkategori}}, {{PLURAL:$3|1 berkas|$3 berkas}})",
+ "search-redirect": "(Dapa pindah dar $1)",
+ "search-section": "(bagian $1)",
+ "search-suggest": "Mangkali ale maksud bagini: $1",
+ "searchall": "samua",
+ "search-showingresults": "{{PLURAL:$4|Hasil <strong>$1</strong> dar <strong>$3</strong>|Hasil <strong>$1 - $2</strong> dar <strong>$3</strong>}}",
+ "search-nonefound": "Seng ada hasil yang cocok deng kriteria",
+ "mypreferences": "Preferensi",
+ "right-writeapi": "Bapake API penulisan",
+ "newuserlogpage": "Log pambiking pangguna baru",
+ "action-edit": "kas bae kintal",
+ "enhancedrc-history": "versi lama",
+ "recentchanges": "Perubahan baru",
+ "recentchanges-legend": "Pilihan parobahan baru-baru",
+ "recentchanges-summary": "Cari parobahan baru dalang wiki di dalang akang kintal.",
+ "recentchanges-noresult": "Seng ada parobahan dalang waktu akang yang cocok deng kriteria.",
+ "recentchanges-feed-description": "Cari parobahan baru dalang wiki di dalang akang umpan",
+ "recentchanges-label-newpage": "Robah sabiji ini la biking kintal baru",
+ "recentchanges-label-minor": "Akang dapa robah sadiki sa",
+ "recentchanges-label-bot": "Bot yang robah akang",
+ "recentchanges-label-unpatrolled": "Parobahan yang balong dipantou",
+ "recentchanges-label-plusminus": "Parobahan ukuran akang kintal dalang bita",
+ "recentchanges-legend-heading": "<strong>Pambiking jelas:</strong>",
+ "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (lia lai [[Special:NewPages|daftar kintal baru]])",
+ "rcnotefrom": "Di bawah {{PLURAL:$5|parobahan}} dar <strong>$3, $4</strong> (dapa kas lia sampe <strong>$1</strong> parobahan).",
+ "rclistfrom": "Kas lia parobahan baru dar $2, $3",
+ "rcshowhideminor": "$1 robahan kacil",
+ "rcshowhideminor-show": "Kas tunjuk kamuka",
+ "rcshowhideminor-hide": "Jang kas lia",
+ "rcshowhidebots": "$1 bot",
+ "rcshowhidebots-show": "Kas tunjuk kamuka",
+ "rcshowhidebots-hide": "Jang kas lia",
+ "rcshowhideliu": "$1 pengguna tadaftar",
+ "rcshowhideliu-show": "Kas tunjuk kamuka",
+ "rcshowhideliu-hide": "Jang kas lia",
+ "rcshowhideanons": "$1 pengguna babayang",
+ "rcshowhideanons-show": "Kas tunjuk kamuka",
+ "rcshowhideanons-hide": "Jang kas lia",
+ "rcshowhidemine": "$1 beta pung daftar parobahan",
+ "rcshowhidemine-show": "Kas tunjuk kamuka",
+ "rcshowhidemine-hide": "Jang kas lia",
+ "rclinks": "Kas lia $1 parobahan baru dalang $2 hari terakhir",
+ "diff": "beda",
+ "hist": "versi",
+ "hide": "Jang kas lia",
+ "show": "Kas tunjuk kamuka",
+ "rc-change-size-new": "$1 {{PLURAL:$1|bita}} kal su barobah",
+ "recentchangeslinked": "Parobahan taika",
+ "recentchangeslinked-toolbox": "Parobahan taika",
+ "recentchangeslinked-title": "Parobahan taika deng \"$1\"",
+ "recentchangeslinked-page": "Kintal pung nama",
+ "recentchangeslinked-to": "Kas lia parobahan dar kintal banya yang tahubung deng kintal yang dong ada sajikan",
+ "upload": "Kas maso berkas",
+ "uploadlogpage": "Log par catat aktivias kas maso di internet",
+ "filedesc": "Ringkasan",
+ "license-header": "Jenis lisensi",
+ "imgfile": "berkas",
+ "file-anchor-link": "Berkas",
+ "filehist": "Berkas pung sejarah",
+ "filehist-help": "Klik tanggal/waktu par lia akang di tanggal/waktu yang diklik",
+ "filehist-current": "sakarang",
+ "filehist-datetime": "Tanggal/Waktu",
+ "filehist-thumb": "Miniatur",
+ "filehist-thumbtext": "Miniatur par versi par $1",
+ "filehist-user": "Pangguna",
+ "filehist-dimensions": "Dimensi",
+ "filehist-comment": "Komentar",
+ "linkstoimage": "{{PLURAL:$1|Kintal berikut}} punya pranala ka akang berkas:",
+ "nolinkstoimage": "Seng ada kintal yang punya sambungan ka akang berkas.",
+ "sharedupload-desc-here": "Akang berkas dar $1 deng mangkali dipake dalang proyek laeng.\nDeskripsi dar [$2 deksripsi pung kintal] dapa kas tunjuk di bawah.",
+ "upload-disallowed-here": "Ale seng bole timpa akang berkas",
+ "randompage": "Halaman sabarang",
+ "nbytes": "$1 {{PLURAL:$1|bita}}",
+ "nmembers": "$1 {{PLURAL:$1|anggota}}",
+ "prefixindex": "Samua kintal deng awalan",
+ "newpages": "Kintal baru",
+ "move": "Kas pindah",
+ "pager-newer-n": "{{PLURAL:$1|1 labe baru|$1 labe baru}}",
+ "pager-older-n": "{{PLURAL:$1|$1 labe lama}}",
+ "booksources": "Sumber buku",
+ "booksources-search-legend": "Cari par sumber buku",
+ "booksources-search": "Cari",
+ "speciallogtitlelabel": "Target (judul ka {{ns:pangguna}}:nama pangguna par pangguna)",
+ "log": "Catatan",
+ "allarticles": "Samua kintal",
+ "allpagessubmit": "Pi",
+ "categories": "Kategori-kategori",
+ "usermessage-editor": "Panyampe pasang sistem",
+ "watchlist": "Daftar pantou",
+ "mywatchlist": "Daftar pantou",
+ "watch": "Pantou",
+ "unwatch": "Seng ka batal pantou",
+ "rollbacklink": "kas kombale",
+ "rollbacklinkcount": "kas kombale $1 {{PLURAL:$1|parobahan}}",
+ "protectedarticle": "kas lindung \"[[$1]]\"",
+ "protect-default": "Kas izin samua pangguna",
+ "restriction-edit": "Kas ubah",
+ "restriction-move": "Kas pindah",
+ "namespace": "Tampa nama",
+ "invert": "Kas kombale yang ale su pilih",
+ "tooltip-invert": "Kas tanda par seng kas lia kintal pung parobahan dalang tampa nama yang su dipilih (ka tampa nama laeng yang taika kal dapa kas tanda)",
+ "namespace_association": "Tampa nama taika",
+ "tooltip-namespace_association": "Kas tanda kintal par taro tampa nama par basuara ka subjek taika deng tampa nama tapilih",
+ "blanknamespace": "(Muka)",
+ "contributions": "Kontribusi {{GENDER:$1|pangguna}}",
+ "contributions-title": "Kontribusi pangguna par $1",
+ "mycontris": "Kontribusi",
+ "anoncontribs": "Kontribusi",
+ "contribsub2": "Voor {{GENDER:$3|$1}} ($2)",
+ "uctop": "(sakarang)",
+ "month": "Dar bulan (deng sabalong)",
+ "year": "Dar taong (deng sabalong):",
+ "sp-contributions-newbies": "Kas lia yang dar pangguna baru sa",
+ "sp-contributions-blocklog": "catatan blokir",
+ "sp-contributions-uploads": "Kas maso ka internet",
+ "sp-contributions-logs": "log",
+ "sp-contributions-talk": "basumbang suara",
+ "sp-contributions-search": "Cari kontribusi",
+ "sp-contributions-username": "IP pung alamat ka nama pangguna:",
+ "sp-contributions-toponly": "Kas lia versi paleng atas sa",
+ "sp-contributions-newonly": "Kas lia cuma yang biking kintal baru sa",
+ "sp-contributions-submit": "Cari",
+ "whatlinkshere-title": "Kintal yang ada pranala ka \"$1\"",
+ "whatlinkshere-page": "Kintal",
+ "nolinkshere": "Seng ada halaman yang taika par <strong>[[:$1]]</strong>.",
+ "isredirect": "kintal voor pengalihan",
+ "istemplate": "tranklusi",
+ "whatlinkshere-prev": "{{PLURAL:$1|sabalong $1}}",
+ "whatlinkshere-next": "{{PLURAL:$1|kamuka $1}}",
+ "whatlinkshere-links": "← pranala",
+ "whatlinkshere-hideredirs": "$1 pangalihan",
+ "whatlinkshere-hidetrans": "$1 transklusi",
+ "whatlinkshere-hidelinks": "$1 pranala",
+ "whatlinkshere-filters": "Alat saring",
+ "ipboptions": "2 jam:2 hours,1 hari:1 day,3 hari:3 days,1 minggu:1 week,2 minggu:2 weeks,1 bulan:1 month,3 bulan:3 months,6 bulan:6 months,1 taong:1 year,salamanya:infinite",
+ "blocklink": "blokir",
+ "contribslink": "gabung",
+ "blocklogpage": "Catatan pamblokiran",
+ "blocklogentry": "blokir [[$1]] sampe $2 $3",
+ "export": "Kas ekspor kintal",
+ "thumbnail-more": "Kas basar",
+ "tooltip-pt-userpage": "Kintal {{GENDER:|Ale pung pangguna}}",
+ "tooltip-pt-mytalk": "Kintal par dong bicara di {{GENDER:|ale pung tampa basumbang suara}}",
+ "tooltip-pt-preferences": "Preferensi {{GENDER:|Ale}}",
+ "tooltip-pt-watchlist": "Daftar kintal yang beta pantou",
+ "tooltip-pt-mycontris": "Daftar kontribusi {{GENDER:|Ale}}",
+ "tooltip-pt-login": "Ale sabae nya maso log, la biar akang seng musti diwajibkan",
+ "tooltip-pt-logout": "Kaluar log",
+ "tooltip-pt-createaccount": "Ale dorang dapa saran par biking akun deng maso log, biar kata akang seng wajib",
+ "tooltip-ca-talk": "Pambincaraan halaman isi",
+ "tooltip-ca-edit": "Kas bae kintal",
+ "tooltip-ca-addsection": "Mulai bagian baru",
+ "tooltip-ca-viewsource": "Kintal akang dapa lindu. Ale cuma dapa lia akang pung sumber",
+ "tooltip-ca-history": "Lia versi terakhir sabalong dapa ubah",
+ "tooltip-ca-move": "Kas pindah akang kintal",
+ "tooltip-ca-watch": "Kas maso akang kintal par ale pung daftar lia-jaga",
+ "tooltip-ca-unwatch": "Hapus akang kintal dar ale pung daftar pantou",
+ "tooltip-search": "Sila cari jua dalang wiki ini mo",
+ "tooltip-search-go": "Pi ka kintal deng nama yang parsis bagitu kal tersedia",
+ "tooltip-search-fulltext": "Sila cari halaman yang ada tulisan macang bagini",
+ "tooltip-p-logo": "Ronda ka Halaman Muka",
+ "tooltip-n-mainpage": "Ronda ka Kintal Muka",
+ "tooltip-n-mainpage-description": "Ronda ka Halaman Muka",
+ "tooltip-n-portal": "Tentang projek, apa yang bole ale perbuat, apa yang bole ale lakukang",
+ "tooltip-n-currentevents": "Baku dapa deng informasi tentang kajadiang baru",
+ "tooltip-n-recentchanges": "Daftar prubahan yang baru dalang wiki",
+ "tooltip-n-randompage": "Kas kaluar akang sabarang halaman",
+ "tooltip-n-help": "Tampa par dapa tolong",
+ "tooltip-t-whatlinkshere": "Daftar samua wiki yang ada punya pranala par akang halaman",
+ "tooltip-t-recentchangeslinked": "Parobahan akhir-akhir dar kintal yang punya pranala par akang kintal",
+ "tooltip-feed-atom": "Umpan Atom par kintal akang",
+ "tooltip-t-contributions": "Daftar kontribusi dar {{GENDER:$1|pangguna akang}}",
+ "tooltip-t-upload": "Kas maso berkas",
+ "tooltip-t-specialpages": "Muatan samua halaman istimewa e",
+ "tooltip-t-print": "Kintal akang dalang versi tacetak",
+ "tooltip-t-permalink": "Pranala permanen par akang kintal pung revisi",
+ "tooltip-ca-nstab-main": "Lia kintal pung isi",
+ "tooltip-ca-nstab-user": "Lia pangguna pung kintal",
+ "tooltip-ca-nstab-special": "Akang ni kintal spesial, seng dapa ubah",
+ "tooltip-ca-nstab-project": "Lia proyek pung kintal",
+ "tooltip-ca-nstab-image": "Lia berkas pung kintal",
+ "tooltip-ca-nstab-mediawiki": "Lia pasang pung sistem",
+ "tooltip-ca-nstab-template": "Lia templat",
+ "tooltip-ca-nstab-category": "Lia kategori pung kintal",
+ "tooltip-minoredit": "Kas tanda akang, akang ni robah sadiki sa",
+ "tooltip-save": "Simpang ale pung parobahan",
+ "tooltip-preview": "Lia sakali lai ale pung parobahan. Pake ini jual sabalom manyimpang.",
+ "tooltip-diff": "Kas lia parobahan yang ale su ada biking",
+ "tooltip-compareselectedversions": "Lia beda dar dua versi kintal yang dipilih",
+ "tooltip-watch": "Kas maso akang kintal dalang ale pung daftar pantou",
+ "tooltip-rollback": "\"Kas bale\" kas batal samua dong ada robah ka versi paleng baru dalang satu klik sa",
+ "tooltip-summary": "Kas maso ringkasan pendek",
+ "simpleantispam-label": "Par periksa anti-manyampah.\n<strong>Jangan</strong> isi akang!",
+ "pageinfo-title": "Informasi par \"$1\"",
+ "pageinfo-header-basic": "Informasi dasar",
+ "pageinfo-header-edits": "Sejarah parobahan",
+ "pageinfo-header-restrictions": "Kintal pung perlindungan",
+ "pageinfo-display-title": "Kapala judul par ditampilkan",
+ "pageinfo-default-sort": "Konci taurut taika",
+ "pageinfo-length": "Kintal pung panjang (dalang bita)",
+ "pageinfo-article-id": "Kintal pung ID",
+ "pageinfo-language": "Dalang kintal pung bahasa",
+ "pageinfo-content-model": "Dalang kintal pung model",
+ "pageinfo-robot-policy": "Indeks samua disusun oleh robot",
+ "pageinfo-watchers": "Samua yang pantou kintal",
+ "pageinfo-redirects-name": "Samua pengalihan ka akang kintal",
+ "pageinfo-firstuser": "Kintal pung pambiking",
+ "pageinfo-firsttime": "Biking kintal pung tanggal",
+ "pageinfo-lastuser": "Parobah terakhir",
+ "pageinfo-lasttime": "Parobahan terakhir pung tanggal",
+ "pageinfo-edits": "Total samua parobahan",
+ "pageinfo-authors": "Samua penulis berbeda pung jumlah",
+ "pageinfo-recent-edits": "Jumlah yang da robah (dalang $1 terakhir)",
+ "pageinfo-recent-authors": "Samua penulis sakarang pung jumlah",
+ "pageinfo-toolboxlink": "Kintal pung info",
+ "previousdiff": "← Revisi sabalongnya",
+ "nextdiff": "Revisi kamuka →",
+ "file-info-size": "$1 × $2 piksel, berkas pung ukuran: $3, tipe MIME: $4",
+ "file-nohires": "Seng ada resoulusi yang labe tinggi",
+ "svg-long-desc": "Berkas SVG, nominal $1 × $2 piksel, basar berkas: $3",
+ "show-big-image": "Ukuran batol-batol",
+ "show-big-image-preview": "Ukuran akang ini: $1.",
+ "show-big-image-other": "{{PLURAL:$2|Resolusi}} laeng: $1.",
+ "show-big-image-size": "$1 x $2 piksel",
+ "bad_image_list": "Formatnya sebagai berikut:\n\nCuma sabutir daftar (baris yang awal e ada tanda *) yang di itong. Pranala yang pertama di suatu baris musti ke benda yang busu. Pranala isalanjutnya pada baris akang jua dianggap sbagai pengecualian, yaitu halaman yang dapa kas kluar akang.",
+ "metadata": "Metadata",
+ "metadata-fields": "Metadata gambar pung bidang dalam akang pasang, bakal katong kas maso dalang kintal gambar pung tampilan kal metadata pung tabel su dikase kacil.\nData laeng dong seng kas lia secara bawaan.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+ "exif-orientation": "Arah",
+ "exif-xresolution": "Resolusi horizontal",
+ "exif-yresolution": "Resolusi vertikal",
+ "exif-datetime": "Tanggal deng waktu parobahan berkas",
+ "exif-make": "Pambiking kamera",
+ "exif-model": "Jenis kamera",
+ "exif-software": "Parangka lombo",
+ "exif-exifversion": "Versi Exif",
+ "exif-colorspace": "Tampa warna",
+ "exif-datetimeoriginal": "Tanggal deng waktu par biking data",
+ "exif-datetimedigitized": "Tanggal deng waktu voor kas digital",
+ "exif-orientation-1": "Normal",
+ "namespacesall": "samua",
+ "monthsall": "samua",
+ "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|basuara]])",
+ "specialpages": "Kintal spesial",
+ "tag-filter": "Alat saring [[Special:Tags|tag]]:",
+ "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag}}]]: $2)",
+ "logentry-delete-delete": "$1 {{GENDER:$2|manghapus}} kintal $3",
+ "logentry-move-move": "$1 {{GENDER:$2|kas pindah}} kintal $3 ka $4",
+ "logentry-move-move_redir": "$1 {{GENDER:$2|kas pindah}} kintal $3 ke $4 kas tutup yang lama",
+ "logentry-newusers-create": "$1 {{GENDER:$2|biking}} akun pangguna",
+ "logentry-upload-upload": "$1 {{GENDER:$2|kas maso di internet}} $3",
+ "searchsuggest-search": "Cari {{SITENAME}}",
+ "duration-days": "$1 {{PLURAL:$1|hari}}"
+}
"permissionserrorstext": "Droëneuh hana geupeuidin keu neupubuët nyoë, muroë {{PLURAL:$1|dalèh}} nyoë:",
"permissionserrorstext-withaction": "Droëneuh hana hak tamöng keu $2, muroë {{PLURAL:$1|choë|choë}} nyoë:",
"recreate-moveddeleted-warn": "'''Ingat: Droëneuh neupeugöt ulang saboh laman nyang ka tom geusampôh. ''',\n\nNeutimang-timang dilèë peuë ék patôt neupeulanjut atra nyang teungöh neu’andam.\nNyoë pat nakeuh log seunampôh nibak laman nyoë:",
- "moveddeleted-notice": "Laman nyoë ka geusampôh.\nLog seunampôh ngön log pinah laman nyoë geupeuseudia di yup nyoë keu keuneubah.",
+ "moveddeleted-notice": "Mieng nyoë ka geusampôh.\nLog seunampôh, neulindông ngön peuninah keu mieng nyoe na di yup nyoe keu catatan.",
"log-fulllog": "Eu ban dum ceunatat",
"edit-hook-aborted": "Seunampôh geupeubateuë lé kaw'ét parser.\nHana jeuneulaih.",
"edit-gone-missing": "Han jeut peubarô ôn.\nÔn nyoe mungkén ka geusampôh.",
"mergelog": "Peugabông log",
"revertmerge": "Hana jadèh peugabông",
"history-title": "Riwayat geunantoë nibak \"$1\"",
+ "difference-title": "Bida antara revisi nibak \"$1\"",
"lineno": "Baréh $1:",
"compareselectedversions": "Peubandéng curak teupiléh",
"editundo": "pubateuë",
"diff-empty": "(Hana bida)",
+ "diff-multi-sameuser": "({{PLURAL:$1|Saboh revisi antara|$1 revisi antara}} lé ureueng ngui nyang saban hana geupeudeuih)",
"searchresults": "Hasé mita",
"searchresults-title": "Hasé mita keu \"$1\"",
"notextmatches": "Hana naseukah laman nyang pah",
"recentchangeslinked-feed": "Neuubah meuhubông",
"recentchangeslinked-toolbox": "Neuubah teukaw'èt",
"recentchangeslinked-title": "Neuubah nyang meukaw'èt ngön $1",
- "recentchangeslinked-summary": "Nyoë nakeuh dapeuta neuubah nyang geupeugèt ban-ban nyoë keu on-on nyang meuhubông nibak ôn ka kusuih (atawa keu anggèëta kawan kusuih).\nÔn-ôn bak [[Special:Watchlist|keunalon droeneuh]] geucitak '''teubay'''.",
+ "recentchangeslinked-summary": "Neupasoe saboh nan mieng keu neueu neuubah bak mieng nyang mupawôt u atawa nibak mieng nyan. (Keu neueu anggèeta nibak saboh kawan, neupasoe Kawan:Nan kawan). Neuubah bak mieng bak [[Special:Watchlist|dapeuta keunalön]] teutuléh <strong>teubai</strong>.",
"recentchangeslinked-page": "Nan miëng:",
"recentchangeslinked-to": "Peuleumah neuubah nibak laman-laman nyang mupawôt ngön laman nyang geubri",
"upload": "Peutamöng beureukaih",
"pager-older-n": "{{PLURAL:$1|1 leubèh awai|$1 leubèh awai}}",
"booksources": "Nè kitab",
"booksources-search-legend": "Mita bak nè kitab",
+ "booksources-search": "Mita",
"specialloguserlabel": "Ureuëng ngui:",
"speciallogtitlelabel": "Sasaran (judu atawa {{ns:ureueng ngui}}:nan ureueng ngui keu ureueng ngui)",
"log": "Log",
"tag-filter-submit": "Saréng",
"tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag}}]]: $2)",
"logentry-delete-delete": "$1 {{GENDER:$2|geusampôh}} miëng $3",
+ "logentry-move-move": "$1 {{GENDER:$2|geupinah}} mieng $3 u $4",
"logentry-newusers-create": "$1 {{GENDER:$2|geupeugöt}} akun ureuëng ngui",
"logentry-upload-upload": "$1 {{GENDER:$2|geupasoe}} $3",
"searchsuggest-search": "Mita {{SITENAME}}",
"unlinkaccounts": "إزالة ربط الحسابات",
"unlinkaccounts-success": "الحساب تم فك وصله.",
"authenticationdatachange-ignored": "تغيير بيانات التحقق لم يتم التعامل معه. ربما لم يتم ضبط موفر؟",
- "userjsispublic": "من فضلك لاحظ: صفحات الجافاسكريبت الفرعية لا ينبغي أن تحتوي غلى بيانات سرية بما أنها يمكن رؤيتها بواسطة المستخدمين الآخرين.",
+ "userjsispublic": "'''من فضلك لاحظ:''' صفحات الجافاسكريبت الفرعية لا ينبغي أن تحتوي على بياناتٍ سرية، وذلك لأنه يمكن مشاهدتها بواسطة المستخدمين الآخرين.",
"userjsonispublic": "الرجاء ملاحظة أنه: يجب ألا تحتوي الصفحات الفرعية لجسون على بيانات سرية لأنها قابلة للعرض من قبل المستخدمين الآخرين.",
"usercssispublic": "من فضل لاحظ: صفحات الCSS الفرعية لا ينبغي أن تحتوي على بيانات سرية بما أنها يمكن رؤيتها بواسطة المستخدمين الآخرين.",
"restrictionsfield-badip": "عنوان أيبي أو نطاق غير صحيح: $1",
"prefs-dateformat": "Formatu de data",
"prefs-timeoffset": "Diferencia horaria",
"prefs-advancedediting": "Opciones xenerales",
+ "prefs-developertools": "Ferramientes pa desendolcadores",
"prefs-editor": "Editor",
"prefs-preview": "Vista previa",
"prefs-advancedrc": "Opciones avanzaes",
"compareselectedversions": "Seçilən versiyaları müqayisə et",
"showhideselectedversions": "Seçilən versiyaları göstər/gizlə",
"editundo": "əvvəlki halına qaytar",
+ "diff-empty": "(Fərqli deyil)",
"diff-multi-sameuser": "(Eyni istifadəçi tərəfindən edilmiş {{PLURAL:$1|bir dəyişiklik|$1 bir neçə dəyişiklik}} göstərilmir)",
"diff-multi-manyusers": "({{PLURAL:$2|Bir istifadəçi|$2 istifadəçi}} tərəfindən edilən {{PLURAL:$1|bir ara redaktə|$1 ara redaktə}} göstərilmir)",
"difference-missing-revision": "Səhifənin {{PLURAL:$2|bu versiyasının|$2 versiyalarının}} müqayisəsi ($1) tapılmadı.\nBu xəta adətən, köhnəlmiş səhifələrin müqayisə versiyalarından keçid edildikdə baş verir.\nDaha ətraflı məlumat üçün [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} silmə qeydlərinə] baxın.",
"search-redirect": "($1 səhifəsindən yönləndirmə)",
"search-section": "(bölmə $1)",
"search-category": "(kateqoriya $1)",
+ "search-file-match": "(faylın məzmunu ilə oxşardır)",
"search-suggest": "Bəlkə, bunu nəzərdə tuturdunuz: $1",
"search-interwiki-caption": "Qonşu layihələrdəki nəticələr",
"search-interwiki-default": "$1 nəticələri:",
"tooltip-pt-login": "Daxil olmanız tövsiyə olunur, amma bu məcburi tələb deyil.",
"tooltip-pt-logout": "Sistemdən çıx",
"tooltip-ca-talk": "Məqalə haqqındə müzakirə edib, münasibətivi bildir",
- "tooltip-ca-edit": "Bu səhifəni redaktə edə bilərsiniz. Lütfən əvvəlcə sınaq gostərişi edin.",
+ "tooltip-ca-edit": "Bu səhifəni redaktə et",
"tooltip-ca-addsection": "Yeni bölmə yarat",
"tooltip-ca-viewsource": "Bu səhifə dəyişikliklərdən mühafizə olunur. Amma siz onun mətninə baxa və mətnin surətini köçürə bilərsiniz.",
"tooltip-ca-history": "Bu səhifənin keçmiş nüsxələri.",
"tooltip-t-recentchangeslinked": "Bu məqaləyə aid başqa səhifələrdə yeni dəyişikliklər",
"tooltip-feed-rss": "Bu səhifə üçün RSS yayımı",
"tooltip-feed-atom": "Bu səhifə üçün Atom yayımı",
- "tooltip-t-contributions": "Bu istifadəçinin redaktə etdiyi səhifələrin siyahısı",
+ "tooltip-t-contributions": "{{GENDER:$1|this user}} adlı istifadəçinin redaktə etdiyi səhifələrin siyahısı",
"tooltip-t-emailuser": "{{GENDER:$1|Bu istifadəçiyə}} e-məktub göndər",
"tooltip-t-upload": "Yeni şəkil və ya multimedia faylı yüklə",
"tooltip-t-specialpages": "Xüsusi səhifələrin siyahısı",
"pageinfo-visiting-watchers": "Səhifəni izləmədə saxlayanlardan son dəyişiklikləri görənlərin sayı",
"pageinfo-few-watchers": "$1 {{PLURAL:$1|izləyicidən|izləyicilərdən}} az",
"pageinfo-redirects-name": "Bu səhifəyə yönləndirmələrin sayı",
+ "pageinfo-subpages-name": "Bu səhifənin alt-səhifələrinin sayı",
"pageinfo-firstuser": "Səhifəni yaradan",
"pageinfo-firsttime": "Səhifənin yaranma tarixi",
"pageinfo-lastuser": "Sonuncu redaktor",
"version-entrypoints-header-url": "URL",
"version-libraries-library": "Kitabxana",
"version-libraries-authors": "Müəlliflər",
+ "redirect-submit": "Keç",
+ "redirect-lookup": "Bax",
"redirect-user": "İstifadəçi ID-si",
"redirect-page": "Səhifənin identifikatoru",
+ "redirect-revision": "Səhifənin versiyası",
+ "redirect-file": "Fayl adı",
"fileduplicatesearch": "Dublikat fayl axtarışı",
"fileduplicatesearch-filename": "Fayl adı:",
"fileduplicatesearch-submit": "Axtar",
"rcfilters-filter-user-experience-level-registered-label": "Зарэгістраваныя",
"rcfilters-filter-user-experience-level-registered-description": "Рэдактары, якія ўвайшлі ў сыстэму.",
"rcfilters-filter-user-experience-level-unregistered-label": "Незарэгістраваныя",
- "rcfilters-filter-user-experience-level-unregistered-description": "Рэдактары, якія не ўвайшлі ў сыстэму",
+ "rcfilters-filter-user-experience-level-unregistered-description": "Рэдактары, якія не ўвайшлі ў сыстэму.",
"rcfilters-filter-user-experience-level-newcomer-label": "Навічкі",
"rcfilters-filter-user-experience-level-newcomer-description": "Зарэгістраваныя рэдактары, якія маюць менш чым 10 правак ці 4 дні актыўнасьці.",
"rcfilters-filter-user-experience-level-learner-label": "Вучні",
"boteditletter": "р",
"number_of_watching_users_pageview": "[$1 {{PLURAL:$1|назіральнік|назіральнікі|назіральнікаў}}]",
"rc-change-size-new": "$1 {{PLURAL:$1|байт|байты|байтаў}} пасьля зьмены",
- "newsectionsummary": "/* $1 */ новая сэкцыя",
+ "newsectionsummary": "/* $1 */ новы разьдзел",
"rc-enhanced-expand": "Паказаць падрабязнасьці",
"rc-enhanced-hide": "Схаваць падрабязнасьці",
"rc-old-title": "зь першапачатковай назвай «$1»",
"recentchangeslinked-feed": "Зьвязаныя праўкі",
"recentchangeslinked-toolbox": "Зьвязаныя праўкі",
"recentchangeslinked-title": "Зьвязаныя праўкі для «$1»",
- "recentchangeslinked-summary": "Увядзіце назву старонкі, каб пабачыць зьмены старонак, на якія яна спасылаецца або якія спасылаюцца на яе (каб пабачыць старонкі з катэгорыі, увядзіце Катэгорыя:Назва). Зьмены старонак з [[Special:Watchlist|вашага сьпісу назіраньня]] пазначаныя <strong>тоўстым шрыфтам</strong>.",
+ "recentchangeslinked-summary": "Увядзіце назву старонкі, каб пабачыць зьмены старонак, на якія яна спасылаецца або якія спасылаюцца на яе (каб пабачыць старонкі з катэгорыі, увядзіце {{ns:category}}:Назва). Зьмены старонак з [[Special:Watchlist|вашага сьпісу назіраньня]] пазначаныя <strong>тоўстым шрыфтам</strong>.",
"recentchangeslinked-page": "Назва старонкі:",
"recentchangeslinked-to": "Замест гэтага паказваць зьмены на старонках, што спасылаюцца на гэтую старонку",
"recentchanges-page-added-to-category": "[[:$1]] дададзеная да катэгорыі",
"tag-mw-rollback": "Адкат",
"tag-mw-rollback-description": "Праўкі, якія адкатваюць папярэднія рэдагаваньні з дапамогай спасылкі адкату",
"tag-mw-undo": "Адмена",
- "tag-mw-undo-description": "Праўкі, якія адмяняць папярэднія праўкі з дапамогай спасылкі адмены праўкі",
+ "tag-mw-undo-description": "Ð\9fÑ\80аÑ\9eкÑ\96, Ñ\8fкÑ\96Ñ\8f адмÑ\8fнÑ\8fÑ\8eÑ\86Ñ\8c папÑ\8fÑ\80Ñ\8dднÑ\96Ñ\8f пÑ\80аÑ\9eкÑ\96 з дапамогай Ñ\81паÑ\81Ñ\8bлкÑ\96 адменÑ\8b пÑ\80аÑ\9eкÑ\96",
"tags-title": "Меткі",
"tags-intro": "На гэтай старонцы знаходзіцца сьпіс метак, якімі праграмнае забесьпячэньне можа пазначыць рэдагаваньне, і іх значэньне.",
"tags-tag": "Назва меткі",
},
"tog-underline": "Падкрэсліваць спасылкі:",
"tog-hideminor": "Не паказваць дробныя праўкі",
- "tog-hidepatrolled": "Без паказу ўхваленых правак у нядаўніх змяненнях",
- "tog-newpageshidepatrolled": "Без паказу ўхваленых правак у пераліку новых старонак",
+ "tog-hidepatrolled": "Без паказу дагледжаных правак у апошніх зменах",
+ "tog-newpageshidepatrolled": "Без паказу дагледжаных правак у пераліку новых старонак",
"tog-hidecategorization": "Схаваць катэгорызацыю старонак",
"tog-extendwatchlist": "Паказваць усе змяненні, а не толькі апошнія",
"tog-usenewrc": "Групаваць змены па старонках у апошніх зменах і спісе назірання",
"tog-shownumberswatching": "Паказваць колькасць назіральнікаў",
"tog-oldsig": "Ваш цяперашні подпіс:",
"tog-fancysig": "Апрацоўваць подпіс як вікі-тэкст (без аўтаматычнай спасылкі)",
- "tog-uselivepreview": "Паказваць папярэдні прагля без перазагрузкі старонкі",
+ "tog-uselivepreview": "Паказваць папярэдні прагляд без перазагрузкі старонкі",
"tog-forceeditsummary": "Папярэджваць пра пустое поле тлумачэння праўкі",
"tog-watchlisthideown": "Не паказваць маіх правак са спісу назірання",
"tog-watchlisthidebots": "Не паказваць праўкі ботаў са спісу назірання",
"tog-watchlisthidepatrolled": "Не паказваць ухваленых правак у старонках са спісу назірання",
"tog-watchlisthidecategorization": "Схаваць катэгорызацыю старонак",
"tog-ccmeonemails": "Слаць мне копіі маіх лістоў",
- "tog-diffonly": "Не паказваць рэшты старонкі пад розніцай",
+ "tog-diffonly": "Не паказваць змест старонкі пад параўнаннем двух версій",
"tog-showhiddencats": "Паказаць схаваныя катэгорыі",
"tog-norollbackdiff": "Не паказваць розніцу ў выніку адкату",
"tog-useeditwarning": "Папярэдзіць мяне, калі я пакідаю старонку з незахаванымі праўкамі",
"prefs-dateformat": "Фармат даты",
"prefs-timeoffset": "Часавы пояс",
"prefs-advancedediting": "Агульныя настройкі",
+ "prefs-developertools": "Інструменты распрацоўшчыка",
"prefs-editor": "Рэдактар",
"prefs-preview": "Перадпаказ",
"prefs-advancedrc": "Пашыраныя настройкі",
"rcfilters-filter-user-experience-level-newcomer-label": "Навічкі",
"rcfilters-filter-user-experience-level-newcomer-description": "Зарэгістраваныя рэдактары, якія маюць менш за 10 правак або 4 дзён актыўнасці.",
"rcfilters-filter-user-experience-level-learner-label": "Вучні",
- "rcfilters-filter-user-experience-level-learner-description": "Ð\97аÑ\80Ñ\8dгÑ\96Ñ\81Ñ\82Ñ\80аванÑ\8bÑ\8f Ñ\80Ñ\8dдакÑ\82аÑ\80Ñ\8b, вопÑ\8bÑ\82 Ñ\8fкÑ\96Ñ\85 знаÑ\85одзÑ\96Ñ\86Ñ\86а памÑ\96ж «навÑ\96Ñ\87камÑ\96» Ñ\96 «даÑ\81ведÑ\87анÑ\8bмÑ\96 Ñ\83дзельнікамі».",
+ "rcfilters-filter-user-experience-level-learner-description": "Ð\97аÑ\80Ñ\8dгÑ\96Ñ\81Ñ\82Ñ\80аванÑ\8bÑ\8f Ñ\80Ñ\8dдакÑ\82аÑ\80Ñ\8b, вопÑ\8bÑ\82 Ñ\8fкÑ\96Ñ\85 знаÑ\85одзÑ\96Ñ\86Ñ\86а памÑ\96ж «навÑ\96Ñ\87камÑ\96» Ñ\96 «вопÑ\8bÑ\82нÑ\8bмÑ\96 Ñ\9eдзельнікамі».",
"rcfilters-filter-user-experience-level-experienced-label": "Вопытныя ўдзельнікі",
"rcfilters-filter-user-experience-level-experienced-description": "Зарэгістраваныя рэдактары з больш за 500 правак і 30 дзён актыўнасці.",
"rcfilters-filtergroup-automated": "Аўтаматызаваны ўнёсак",
"rcfilters-filter-major-description": "Праўкі, не пазначаныя як дробныя.",
"rcfilters-filtergroup-watchlist": "Старонкі ў спісе назірання",
"rcfilters-filter-watchlist-watched-label": "У спісе назірання",
- "rcfilters-filter-watchlist-watched-description": "Змяненні старонак у Вашым спісе назірання.",
- "rcfilters-filter-watchlist-watchednew-label": "Новыя змяненні ў спісе назірання",
+ "rcfilters-filter-watchlist-watched-description": "Змены ў старонках з Вашага спісу назірання.",
+ "rcfilters-filter-watchlist-watchednew-label": "Новыя змены ў спісе назірання",
"rcfilters-filter-watchlist-watchednew-description": "Праўкі на старонках з Вашага спісу назірання, якія Вы не праглядалі з часу іх здзяйснення.",
"rcfilters-filter-watchlist-notwatched-label": "Не ў спісе назірання",
"rcfilters-filter-watchlist-notwatched-description": "Усё за выключэннем правак старонак з Вашага спісу назірання.",
"rcfilters-liveupdates-button-title-off": "Паказваць навыя змены адразу пасля іх з’яўлення",
"rcfilters-watchlist-markseen-button": "Пазначыць усе змены як прагледжаныя",
"rcfilters-watchlist-edit-watchlist-button": "Рэдагаваць Ваш спіс назіраных старонак",
+ "rcfilters-watchlist-showupdated": "Змены старонак, якія Вы не наведвалі з таго часу, як яны адбыліся, выдзелены <strong>тлустым</strong> і пазначаны маркерам.",
"rcfilters-preference-label": "Схаваць палепшаную версію «Апошніх змен»",
"rcfilters-preference-help": "Адкатвае рэдызайн інтэрфейсу 2017 года і ўсе інструменты, дададзеныя з тых часоў.",
"rcnotefrom": "Ніжэй {{PLURAL:$5|паказана змяненне|паказаны змены}} з <strong>$3, $4</strong> (не больш за <strong>$1</strong>).",
"tag-filter-submit": "Фільтр",
"tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Тэг|Тэгі}}]]: $2)",
"tag-mw-contentmodelchange": "змена мадэлі змесціва",
+ "tag-mw-contentmodelchange-description": "Праўкі, якія [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel мяняюць мадэль змесціва] старонкі",
"tag-mw-new-redirect": "Новая перасылка",
+ "tag-mw-new-redirect-description": "Праўкі, якімі створаны перасылкі або старонкі заменены на перасылкі",
"tag-mw-removed-redirect": "Выдаленае перанакіраванне",
- "tag-mw-changed-redirect-target": "Змяненне мэты перенаправления",
+ "tag-mw-removed-redirect-description": "Праўкі, якія замяняюць існуючую перасылку на не-перасылку",
+ "tag-mw-changed-redirect-target": "Змяненне мэты перасылкі",
+ "tag-mw-changed-redirect-target-description": "Праўкі, якія змяняюць мэту перасылкі",
"tag-mw-blank": "ачыстка",
- "tag-mw-blank-description": "Праўкі, ачышчальныя гэтую старонку",
+ "tag-mw-blank-description": "Праўкі, якія ачышчаюць старонку",
"tag-mw-replace": "Заменена",
- "tag-mw-rollback": "адкат",
- "tag-mw-undo": "адмена",
+ "tag-mw-replace-description": "Праўкі, якія выдаляюць больш за 90% зместу старонкі",
+ "tag-mw-rollback": "Адкат",
+ "tag-mw-rollback-description": "Праўкі, якія адкатваюць папярэднія праўкі з дапамогай спасылкі адкату",
+ "tag-mw-undo": "Адмена",
+ "tag-mw-undo-description": "Праўкі, якія адмяняюць папярэднія праўкі з дапамогай спасылкі адмены праўкі",
"tags-title": "Біркі",
"tags-intro": "Тут пералічаныя біркі, якімі праграмы могуць пазначыць праўку, а таксама іх значэнні.",
"tags-tag": "Назва біркі",
"mw-widgets-mediasearch-input-placeholder": "Пошук мультымедыя",
"mw-widgets-titleinput-description-new-page": "старонка яшчэ не існуе",
"mw-widgets-titleinput-description-redirect": "перанакіраванне на $1",
+ "mw-widgets-usersmultiselect-placeholder": "Дадаць яшчэ...",
"date-range-from": "Ад даты:",
"date-range-to": "Да даты:",
"randomrootpage": "Выпадковая карэнная старонка",
"tog-watchlisthideminor": "धियानसूची से छोट संपादन छिपावल जाय",
"tog-watchlisthideliu": "खाता में प्रवेश भइल प्रयोगकर्ता लोग के संपादन धियानसूची से छिपावल जाय",
"tog-watchlistreloadautomatically": "जब कौनों फिल्टर बदलल जाय तब धियानसूची ऑटोमेटिक दोबारा लोड होखे (जावास्क्रिप्ट जरूरी)",
+ "tog-watchlistunwatchlinks": "धियान में राखल जवना पन्ना सभ में बदलाव भइल बा उनहन में बिनाधियान/धियान के चीन्हा सभ ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}) के सीधे जोड़ीं (एह टॉगल सुबिधा खातिर जावास्क्रिप्ट के जरूरत पड़ी)",
"tog-watchlisthideanons": "बेनाम प्रयोगकर्ता लोग के संपादन धियानसूची से छिपावल जाय",
"tog-watchlisthidepatrolled": "जाँचल गइल संपादन के धियानसूची से छिपावल जाय",
"tog-watchlisthidecategorization": "पन्ना श्रेणीकरण छिपावल जाय",
"cascadeprotected": "ए पन्ना के संपादन कइल सुरक्षित क दिहल गइल बा काहें कि ई {{PLURAL:$1|पन्ना में, जौना के|पन्ना सब में, जिन्हन के}} \"कैस्केडिंग\" (बिस्तारित) सुरक्षा चालू क के सुरक्षित कइल गइल बा, में समाइल बाटे:\n$2",
"namespaceprotected": "रउआ के '''$1''' नामस्थान के पन्नं में सम्पादन करे के अधिकार नइखे दिहल गइल।",
"customcssprotected": "रउआ के इ CSS पन्ना के संपादित करे के अनुमति नइखे, काहे कि इ में अन्य सदस्यं के व्यक्तिगत सेटिंग्स समाविष्ट बा।",
+ "customjsonprotected": "रउआ के एह JSON पन्ना के संपादित करे के इजाजत नइखे, काहें कि एह में दुसरे प्रयोगकर्ता ब्यक्तिगत सेटिंग सामिल बा।",
"customjsprotected": "रउआ इ जावास्क्रिप्ट पन्ना के संपादित करे के अनुमति नइखे, काहे कि इ में अन्य सदस्यं के व्यक्तिगत सेटिंग्स समाविष्ट बा।",
"mycustomcssprotected": "रउआ इ CSS के पन्ना के सम्पादित करे के अधिकार नइखे।",
+ "mycustomjsonprotected": "आपके एह JSON पन्ना में संपादन के इजाजत नइखे।",
"mycustomjsprotected": "रउआ इ जावास्क्रिप्ट पन्ना के सम्पादित करे के अधिकार नइखे।",
"myprivateinfoprotected": "रउआ लगे आपन व्यक्तिगत जानकारी बदले के अनुमति नइखे।",
"mypreferencesprotected": "रउआ लगे आपन वरियतां (पसंद) बदले के अधिकार नइखे।",
"wrongpasswordempty": "गुप्तशब्द खाली बा। कृपया फिर से कोसिस करीं।",
"passwordtooshort": "गुप्तशब्द कम से कम {{PLURAL:$1|1 अक्षर|$1 अक्षर}} के होवे के चाहीं।",
"passwordtoolong": "गुप्तशब्द {{PLURAL:$1|$1 अक्षर}} से लमहर ना चाहीं।",
- "passwordtoopopular": "à¤\85à¤\95à¥\8dसरहा बà¥\80à¤\9bल à¤\9cाà¤\8f वाला à¤\97à¥\81पà¥\8dतशबà¥\8dद ना à¤\87सà¥\8dतà¥\87माल हà¥\8b सà¤\95à¥\87 ला। à¤\95à¥\8cनà¥\8bà¤\82 à¤\85à¤\89रà¥\80 à¤\96ास à¤\85लà¤\97 à¤\95िसिम à¤\95à¥\87 à¤\97à¥\81पà¥\8dतशबà¥\8dद à¤\9aà¥\81नà¥\80à¤\82।",
+ "passwordtoopopular": "à¤\85à¤\95à¥\8dसरहा बà¥\80à¤\9bल à¤\9cाà¤\8f वाला à¤\97à¥\81पà¥\8dतशबà¥\8dद ना à¤\87सà¥\8dतà¥\87माल à¤\95à¤\87ल à¤\9cा सà¤\95à¥\87 ला। à¤\85à¤\87सन à¤\97à¥\81पà¥\8dतशबà¥\8dद बà¥\80à¤\9bà¥\80à¤\82 à¤\9cà¥\87à¤\95र à¤\85à¤\82à¤\9cाद लà¤\97ावल ढà¥\87र à¤\95ठिन हà¥\8bà¤\96à¥\87।",
"password-name-match": "राउर गुप्तशब्द राउर प्रयोगकर्तानाँव से अलग होखे के चाहीं।",
"password-login-forbidden": "इस प्रयोगकर्तानाँव आ गुप्तशब्द के प्रयोग वर्जित बा।",
"mailmypassword": "गुप्तशब्द रिसेट करीं",
"passwordremindertitle": "{{SITENAME}} खातिर नया अस्थायी गुप्तशब्द",
- "passwordremindertext": "केहू (शायद रउए, $1 आइपी पता से) {{SITENAME}} ($4) पर प्रयोग खातिर नया गुप्तशब्द के निवेदन कइले बा। प्रयोगकर्ता \"$2\" खातिर एगो अस्थायी गुप्तशब्द बना दिहल गइल बा, आ ई \"$3\" बा। यदि ई रउवें चाहत रहलीं, त अब रउआँ के खाता में प्रवेश क के एगो नया गुप्तशब्द चुने के पड़ी।\nराउर अस्थायी गुप्तशब्द के अवधि {{PLURAL:$5|एक दिन|$5 दिन}} में खतम हो जाई।\n\nयदि ई निवेदन केहु अउर कइले रहल, या रउआँ के आपन पुरनका गुप्तशब्द इयाद आ गइल बा आ बदलाव नइखीं चाहत, त रउआँ ए सनेसा के अनदेखा कर सकत बानी, आ आपन पुरनका गुप्तशब्द के प्रयोग पहिले नियर कर सकत बानी।",
+ "passwordremindertext": "केहू ($1 आइपी पता से) {{SITENAME}} ($4) पर प्रयोग खातिर नया गुप्तशब्द के निवेदन कइले बा। प्रयोगकर्ता \"$2\" खातिर एगो अस्थायी गुप्तशब्द बना दिहल गइल बा, आ ई \"$3\" बा। यदि ई रउवें चाहत रहलीं, त अब रउआँ के खाता में प्रवेश क के एगो नया गुप्तशब्द चुने के पड़ी।\nराउर अस्थायी गुप्तशब्द के समयसीमा {{PLURAL:$5|एक दिन|$5 दिन}} में खतम हो जाई।\n\nयदि ई निवेदन केहु अउर कइले रहल, या रउआँ के आपन पुरनका गुप्तशब्द इयाद आ गइल बा आ बदलाव नइखीं चाहत, त रउआँ ए सनेसा के अनदेखा कर सकत बानी, आ आपन पुरनका गुप्तशब्द के प्रयोग पहिले नियर कर सकत बानी।",
"noemail": "\"$1\" प्रयोगकर्ता खातिर कौनों ईमेल पता रिकार्ड में नइखे।",
"noemailcreate": "रउआँ के एगो जायज ईमेल पता देवे के पड़ी।",
"passwordsent": "\"$1\" के ईमेल पता पर एगो नया गुप्तशब्द भेज दिहल गइल बा।\nईमेल पावे के बाद कृपया दुबारा खाता में प्रवेश करीं।",
"savechanges": "बदलाव सहेजीं",
"publishpage": "पन्ना प्रकाशित करीं",
"publishchanges": "बदलाव प्रकाशित करीं",
+ "savearticle-start": "पन्ना सहेजीं...",
+ "savechanges-start": "बदलाव सहेजीं...",
+ "publishpage-start": "पन्ना प्रकाशित करीं...",
+ "publishchanges-start": "बदलाव प्रकाशित करीं...",
"preview": "झलक",
"showpreview": "झलक देखीं",
"showdiff": "बदलाव देखीं",
"noarticletext-nopermission": "ए पन्ना मे अभी कौनों सामग्री नइखे।\nरउआँ दुसरा पन्ना में [[Special:Search/{{PAGENAME}}|ए टाइटिल के खोज]] कर सकत बानीं,\nया <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} या संबंधित लॉग खोज सकत बानी]</span>, बाकी रउआ के ई पन्ना बनावे के परमीशन नइखे।",
"missing-revision": "\"{{FULLPAGENAME}}\" पन्ना के संशोधन #$1 उपलब्ध नइखे।\n\nसाधारण रुप से इ एगो हटावल गइल पन्ना के पुरान लिंक पर क्लिक कइला से होखेला।\nअधिक जानकारी खातिर आप [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} हटावे के लॉग] देख सकत बानी।",
"userpage-userdoesnotexist": "सदस्य खाता \"$1\" पंजीकृत नइखे।\nकृपया जाँच लीं कि आप इ पन्ना संपादित अथवा निर्मित करे के चाहत बानी कि ना।",
- "userpage-userdoesnotexist-view": "सदसà¥\8dय à¤\96ाता \"$1\" पà¤\82à¤\9cà¥\80à¤\95à¥\83त नà¤\88à¤\96à¥\87 à¤à¤\88ल।",
+ "userpage-userdoesnotexist-view": "पà¥\8dरयà¥\8bà¤\97à¤\95रà¥\8dता à¤\96ाता \"$1\" रà¤\9cिसà¥\8dà¤\9fरà¥\8dड नà¤\87à¤\96à¥\87 à¤à¤\87ल।",
"blocked-notice-logextract": "ई प्रयोगकर्ता के ई समय निष्क्रीय कर दिहल गईल बा।\nनविनतम नष्ट लौग प्रविष्टी उद्धरण खातिर निचे दिहल बा:",
"clearyourcache": "<strong>नोट:</strong> सहेजे के बाद, बदलाव देखे खातिर आपके अपने ब्राउजर के कैशे खाली करे के पड़ सकत बा।\n* <strong>फायरफॉक्स / सफारी:</strong><em>शिफ्ट</em> दबा के <em>रीलोड</em> पर क्लिक करीं, या फिर <em>Ctrl-F5</em> या <em>Ctrl-R</em> दबाईं (मैक पर <em>⌘-R</em>)\n* <strong>गूगल क्रोम:</strong> <em>Ctrl-Shift-R</em> दबाईं (मैक पर <em>⌘-Shift-R</em>)\n* <strong>इंटरनेट एक्स्प्लोरर:</strong> <em>Ctrl</em> दबा के <em>Refresh</em> पर क्लिक करीं, या <em>Ctrl-F5</em> दबईं\n* <strong>ओपेरा:</strong> <em>Menu → Settings</em> में जाईं (मैक में <em>Opera → Preferences</em>) आ एकरे बाद <em>Privacy & security → Clear browsing data → Cached images and files</em> क्लिक करीं।",
"usercssyoucanpreview": "<strong>टिप:</strong> आपन नया CSS के टेस्ट करे खातिर सहेजे से पहिले \"{{int:showpreview}}\" बटन के प्रयोग करीं।",
+ "userjsonyoucanpreview": "<strong>टिप:</strong> आपन नया JSON के टेस्ट करे खातिर सहेजे से पहिले \"{{int:showpreview}}\" बटन के प्रयोग करीं।",
"userjsyoucanpreview": "<strong>टिप:</strong> आपन नया जावास्क्रिप्ट के टेस्ट करे खातिर सहेजे से पहिले \"{{int:showpreview}}\" बटन के प्रयोग करीं।",
"usercsspreview": "<strong>याद रहे की आप अपनी सदस्य CSS के खाली नमूना भर देखत बानी।\nई अबहिन ले सहेजल ना गइल बाटे।</strong>",
+ "userjsonpreview": "<strong>याद रहे की आप अपने JSON config के खाली टेस्ट करत बानी/नमूना देखत बानी।\nई अबहिन सहेजल ना गइल बाटे।</strong>",
"userjspreview": "<strong>याद रहे की आप अपनी सदस्य जावास्क्रिप्ट के खाली टेस्ट करत बानी/नमूना देखत बानी।\nई अबहिन सहेजल ना गइल बाटे।</strong>",
"sitecsspreview": "<strong>याद रहे की आप ए CSS क खाली नमूना देखत बानी।\nई अबहिन ले सहेजल ना गइल बा!</strong>",
+ "sitejsonpreview": "<strong>याद रहे की आप ए JSON config क खाली नमूना देखत बानी।\nई अबहिन ले सहेजल ना गइल बा!</strong>",
"sitejspreview": "<strong>याद रहे की आप ए जावास्क्रिप्ट कोड क खाली नमूना देखत बानी।\nई अबहिन ले सहेजल ना गइल बा!</strong>",
- "userinvalidconfigtitle": "<strong>चेतावनी:</strong> कौनों skin \"$1\"नइखे।\nCustom .css आ .js पन्ना सभ छोटका अक्षर में टाइटिल इस्तेमाल करे लें जइसे की, {{ns:user}}:Foo/vector.css ना की {{ns:user}}:Foo/Vector.css।",
+ "userinvalidconfigtitle": "<strong>चेतावनी:</strong> कौनों skin \"$1\"नइखे।\nCustom .css, ,json, आ .js पन्ना सभ छोटका अक्षर में टाइटिल इस्तेमाल करे लें जइसे की, {{ns:user}}:Foo/vector.css ना की {{ns:user}}:Foo/Vector.css",
"updated": "(अपडेट करल गईल)",
"note": "'''सूचना:'''",
- "previewnote": "'''याद रखीं, इ एगो झलक मात्र हो।'''\nराउर बदलाव अभी तक सुरक्षित नईखे करल गईल!",
+ "previewnote": "<strong>याद रखीं, इ एगो झलक भर हवे।</strong>\nराउर बदलाव अभिन सहेजल ना गइल बा!",
"continue-editing": "संपादन क्षेत्र में जाईं",
"previewconflict": "ई नमूना ई देखावत बा की अगर रउआँ ए संपादन बक्सा में मौजूद पाठ के सहेजब त ऊ कइसन देखाई पड़ी।",
"session_fail_preview": "माफ करीं! एह सत्र के आँकड़ा के गायब हो गइला के कारण आपके संपादन के प्रॉसेस करे में हमनी के असमर्थ बानी जा।\nहो सकेला आप लॉगआउट हो गइल होखीं।\n<strong>जाँच लेईं कि आप अभी लॉगिन बानी आ दुबारा कोसिस करीं</strong>।\nअगर तबो काम ना होखे तब [[Special:UserLogout|लॉगआउट कइके]] आ दोबारा लॉग इन कइ के कोसिस करी, आ जाँच करीं कि आपके ब्राउजर एह साइट से कुकीज सभ के मंजूर करत बा।",
"longpageerror": "<strong>खराबी: आप जवन पाठ लिख के दिहले बानी ऊ {{PLURAL:$1|एक किलोबाइट|$1 किलोबाइट्स}} के बाटे, जेवन अधिकतम सीमा {{PLURAL:$2|एक किलोबाइट|$2 किलोबाइट्स}} से ढेर बा।</strong>\nई सहेजल ना जा सकेला।",
"readonlywarning": "<strong>चेतावनी: एह समय मरम्मत खातिर डेटाबेस लॉक कइल गइल बा, एही कारन आप तुरंते एही समय आपन संपादन ना सहेज पाइब।</strong>\nरउआँ अपनी पाठ (टेक्स्ट) के कौनों पाठ फाइल (टेक्स्ट फाइल) में बाद खातिर सहेज के रख लीं।\n\nजे सिस्टम प्रबंधक एकरा के लॉक कइले बा ऊ नीचे लिखल कारण दिहले बा: $1",
"protectedpagewarning": "<strong>चेतावनी: ई पन्ना सुरक्षित कइल गइल बा जेवना से कि एकरा के खाली प्रबंधक (Admin) विशेषाधिकार वाला सदस्य लोग संपादित क सकत बा।</strong>\nप्रसंग बूझे खातिर सबसे नया लॉग एंट्री नीचे दिहल जात बा:",
- "semiprotectedpagewarning": "<strong>नà¥\8bà¤\9f:</strong> à¤\88 पनà¥\8dना सà¥\81रà¤\95à¥\8dषित à¤\95à¤\87ल à¤\97à¤\87ल बा à¤\95ि à¤\8fà¤\95रा à¤\95à¥\87 à¤\96ालà¥\80 रà¤\9cिसà¥\8dà¤\9fरà¥\8dड सदसà¥\8dय लà¥\8bà¤\97 सà¤\82पादित à¤\95 सà¤\95त बा।\nसà¤à¤¸à¥\87 नया लà¥\89à¤\97 à¤\8fà¤\82à¤\9fà¥\8dरà¥\80 नà¥\80à¤\9aà¥\87 पà¥\8dरसà¤\82à¤\97 बतावà¥\87 à¤\96ातिर दिहल जात बा:",
+ "semiprotectedpagewarning": "<strong>नà¥\8bà¤\9f:</strong> à¤\88 पनà¥\8dना सà¥\81रà¤\95à¥\8dषित à¤\95à¤\87ल à¤\97à¤\87ल बा à¤\95ि à¤\8fà¤\95रा à¤\95à¥\87 à¤\96ालà¥\80 à¤\91à¤\9fà¥\8bà¤\95नà¥\8dफरà¥\8dम पà¥\8dरयà¥\8bà¤\97à¤\95रà¥\8dता लà¥\8bà¤\97 सà¤\82पादित à¤\95 सà¤\95त बा।\nनà¥\80à¤\9aà¥\87 पà¥\8dरसà¤\82à¤\97 बतावà¥\87 à¤\96ातिर सà¤à¤¸à¥\87 नया लà¥\89à¤\97 à¤\8fà¤\82à¤\9fà¥\8dरà¥\80 दिहल जात बा:",
"cascadeprotectedwarning": "<strong>चेतावनी:</strong> ई पन्ना सुरक्षित बा जवना से कि खाली [[Special:ListGroupRights|बिसेस अधिकार]] वाला प्रयोगकर्ता लोग संपादन क सकेला काहें से की ई नीचे दिहल गइल छतनार-सुरक्षा वाला {{PLURAL:$1|पन्ना|पन्ना सभ}} में ट्रांसक्लूड हो रहल बाटे:",
"titleprotectedwarning": "<strong>चेतावनी: ई पन्ना सुरक्षित कइल गइल बा की एकरा के बनावे खातिर [[Special:ListGroupRights|विशेष अधिकार]] होखल जरूरी बा।</strong>\nसंदर्भ खातिर नीचे सबसे नया लॉग एंट्री दिहल जात बा:",
"templatesused": "ए पन्ना पर इस्तेमाल {{PLURAL:$1|टेम्पलेट|टेम्पलेट कुल}}:",
"expansion-depth-exceeded-warning": "पन्ना अधिकतम बिस्तार गहिराई के पार क गइल",
"parser-unstrip-loop-warning": "अनस्ट्रिप लूप पकड़ में आइल बा",
"unstrip-depth-warning": "अनस्ट्रिप रिकर्शन सीमा पार हो गइल ($1)",
+ "unstrip-depth-category": "पन्ना जहाँ अनस्ट्रिप गहिराई सीमा पार क चुकल बाटे",
+ "unstrip-size-warning": "अनस्ट्रिप साइज के सीमा पार हो चुकल बा ($1)",
+ "unstrip-size-category": "पन्ना जहाँ अनस्ट्रिप साइज के सीमा पार हो चुकल बाटे",
"converter-manual-rule-error": "मैनुअल भाषा परिवर्तन नियम में खराबी पकड़ल गइल",
"undo-success": "संपादन वापस कइल जा सकत बा।\nनीचे दिहल तुलना के चेक करीं आ पुष्टी करीं की आप इहे कइल चाहत बाड़ीं, ओकरा बाद बदलाव सहेज के संपादन वापसी के पूरा करीं।",
"undo-failure": "बीच में अउरी संपादन होखला की कारण ई संपादन वापस नइखे लिहल जा सकत।",
"revdelete-modify-missing": "आइटम ID $1 के बदलाव करे में खराबी: ई डेटाबेस से गायब बा!",
"revdelete-no-change": "<strong>चेतावनी:</strong> तारीख $2 के $1 बजे के ई आइटम पहिलहीं से ओही देखावे के सेटिंग वाला बाटे जवन माँगल जाता।",
"revdelete-concurrent-change": "$1 $2 बजे के आइटम के बदले में खराबी आ रहल बा: बुझाता कि आप के कोसिस करे दौरान एकरा स्थिति के दूसर केहू बदल चुकल बा।\nलॉग चेक करीं।",
+ "revdelete-only-restricted": "तारीख $2, $1 के आइटम के लुकवावे में खराबी आवत बा: आप प्रबंधक लोग के नजर में आवे से आइटम के ना दबा सकत बाड़ीं जबले कि कौनों अउरी विजिबिलिटी बिकल्प के भी न सेलेक्ट करीं।",
+ "revdelete-reason-dropdown": "*हटावे के आम कारण\n** कॉपीराइट उलंघन\n** अनुचित कमेंट भा पर्सनल जानकारी\n** अनुचित प्रयोगकर्तानाँव\n** मानहानि-कारक जानकारी",
"revdelete-otherreason": "अन्य/अतिरिक्त कारण:",
"revdelete-reasonotherlist": "अन्य कारण",
"revdelete-edit-reasonlist": "हटावे के कारण बदलीं",
"nextn-title": "अगिला $1 {{PLURAL:$1|परिणाम}}",
"shown-title": "प्रति पन्ना $1 {{PLURAL:$1|परिणाम}} देखाईं",
"viewprevnext": "देखीं ($1 {{int:pipe-separator}} $2) ($3)",
- "searchmenu-exists": "'''इ विकि पर ''[[:$1]]'' नाम से एगो पन्ना उपलब्ध बा'''",
+ "searchmenu-exists": "<strong>एह विकि पर \"[[:$1]]\" नाँव से एगो पन्ना मौजूद बा।</strong> {{PLURAL:$2|0=|खोज में मिलल अउरियो रिजल्ट सभ देखीं}}",
"searchmenu-new": "<strong> ए विकि पर \"[[:$1]]\" नाँव के पन्ना बनाईं !</strong> {{PLURAL:$2|0=|अपनी खोज से मिलल पन्ना भी देखीं|खोज के परिणाम भी देखीं।}}",
"searchprofile-articles": "सामग्री पन्ना",
"searchprofile-images": "मल्टीमीडिया",
"licenses-edit": "लाइसेंस बिकल्प संपादन",
"license-nopreview": "(नमूना देखल उपलब्ध नइखे)",
"imgfile": "फाइल",
- "listfiles": "फाà¤\87ल सà¥\82à¤\9aà¥\80",
+ "listfiles": "फाà¤\87ल लिसà¥\8dà¤\9f",
"listfiles_thumb": "चिप्पी",
"listfiles_date": "तिथि",
"listfiles_name": "नाँव",
"filehist-thumbtext": "$1 ले के संस्करण के चिप्पी रूप।",
"filehist-nothumb": "बिन थम्बनेल",
"filehist-user": "प्रयोगकर्ता",
- "filehist-dimensions": "à¤\86याम",
+ "filehist-dimensions": "डाà¤\87मà¥\87à¤\82शन",
"filehist-filesize": "फाईल के आकार",
"filehist-comment": "टिप्पणी",
"imagelinks": "फाइल के उपयोग",
"sharedupload": "इ फाईल $1 से बा आ दुसर परियोजना में प्रयोग करल जा सकत बा।",
"sharedupload-desc-there": "इ फाईल $1 से बा आ दुसर परियोजना में प्रयोग करल जा सकत बा। अधिक जानकारी खातिर कृपया [$2 फाईल विवरण पन्ना] देखीं।",
"sharedupload-desc-here": "ई फाइल $1 से बा आ अउरी प्रोजेक्ट भी एकर इस्तेमाल कर सकत बाड़ें। \nएकर विवरण [$2 फाइल विवरण पन्ना] नीचे देखावल गइल बा।",
- "filepage-nofile": "à¤\87 नाम सà¥\87 à¤\95à¥\8cनà¥\8b फाà¤\88ल à¤\89पलबà¥\8dध नà¤\88खे।",
+ "filepage-nofile": "à¤\8fह नाम सà¥\87 à¤\95à¥\8cनà¥\8b फाà¤\87ल मà¥\8cà¤\9cà¥\82द नà¤\87खे।",
"filepage-nofile-link": "इ नाम से कौनो फाईल उपलब्ध नईखे, लेकिन रउआ [$1 के अपलोड कर] सकत बानी।",
"uploadnewversion-linktext": "इ फाईल के नया संस्करण लादीं।",
"shared-repo-from": "$1 से",
"protectedtitles": "सुरक्षित शीर्षक",
"protectedtitlesempty": "कौनों टाइटिल के सुरक्षा एह पैमान पर नइखे।",
"protectedtitles-submit": "शीर्षक देखीं",
- "listusers": "सदसà¥\8dयसà¥\82à¤\9aà¥\80",
+ "listusers": "पà¥\8dरयà¥\8bà¤\97à¤\95रà¥\8dता लिसà¥\8dà¤\9f",
"listusers-editsonly": "उहे सदस्य देखाईं जे संपादन कइले होखे",
"listusers-creationsort": "बनवले की तारीख की हिसाब से सरियाईं",
"listusers-desc": "घटत क्रम से सरियाईं",
"trackingcategories": "नजर रखे वाला श्रेणीसभ",
"trackingcategories-msg": "निगरानी श्रेणी",
"trackingcategories-name": "संदेस नाँव",
- "emailuser": "à¤\88 प्रयोगकर्ता के ईमेल करीं",
+ "emailuser": "à¤\8fह प्रयोगकर्ता के ईमेल करीं",
"emailusername": "प्रयोगकर्तानाँव:",
"emailfrom": "भेजे वाला:",
"emailto": "पावे वाला:",
"mycontris": "योगदान",
"anoncontribs": "योगदान",
"contribsub2": "{{GENDER:$3|$1}} ($2) खातिर",
- "nocontribs": "à¤\88 मानदà¤\82ड सà¥\87 मिलत à¤\9cà¥\81लत कौनो बदलाव ना मिलल।",
+ "nocontribs": "à¤\8fह पà¥\88माना सà¥\87 मà¥\88à¤\9a à¤\95रत कौनो बदलाव ना मिलल।",
"uctop": "(वर्तमान)",
"month": "महीना से (आ ओ से पहिले):",
"year": "साल से (आ ओ से पहिले):",
"whatlinkshere-title": "पन्ना जेवन \"$1\" से जुड़ल बा",
"whatlinkshere-page": "पन्ना:",
"linkshere": "<strong>[[:$1]]</strong> से नीचे दिहल पन्ना जुड़ल बाने:",
- "nolinkshere": "'''[[:$1]]''' सà¥\87 à¤\95à¥\8cनà¥\8b पनà¥\8dना नà¤\88खे जुड़ल।",
+ "nolinkshere": "'''[[:$1]]''' सà¥\87 à¤\95à¥\8cनà¥\8b पनà¥\8dना नà¤\87खे जुड़ल।",
"nolinkshere-ns": "चुनल गईल सन्दर्भ में '''[[:$1]]''' से कौनो पन्ना ना जुड़ेला।",
"isredirect": "अनुप्रेषित पन्ना",
"istemplate": "ट्रांस्क्लूजन",
"whatlinkshere-hideimages": "$1 फाइल कड़ी",
"whatlinkshere-filters": "छननी",
"blockip": "{{GENDER:$1|सदस्य}} अवरोधित करीं",
- "ipboptions": "२ घंटे:2 hours,१ दिन:1 day,३ दिन:3 days,१ हफ्ता:1 week,२ हफ्ते:2 weeks,१ महिना:1 month,३ महिने:3 months,६ महिने:6 months,१ साल:1 year,हमेशा खातिर:infinite",
+ "ipboptions": "2 घंटा:2 hours,1 दिन:1 day,3 दिन:3 days,1 हप्ता:1 week,2 हप्ता:2 weeks,1 महीना:1 month,3 महीना:3 months,6 महीना:6 months,1 साल:1 year,अनिश्चित समय खातिर:infinite",
"blocklist": "अवरोधित प्रयोगकर्तासभ",
"infiniteblock": "अनिश्चितकाल",
"blocklink": "रोक लगाईं",
"unblocklink": "ताला खोलीं",
"change-blocklink": "ब्लॉक बदलीं",
"contribslink": "योगदान",
- "blocklogpage": "निषà¥\8dà¤\95à¥\8dरिय à¤\96ाता",
+ "blocklogpage": "रà¥\8bà¤\95 लà¥\89à¤\97",
"blocklogentry": "[[$1]] के ब्लॉक कइल गइल, समाप्ती के अवधि $2 $3",
"reblock-logentry": "[[$1]] खातिर रोक सेटिंग बदलल गइल आ अब समाप्ती समय बा $2 $3",
"block-log-flags-nocreate": "खाता निर्माण सक्षम नइखे",
"tooltip-ca-addsection": "एगो नया खंड शुरु करीं",
"tooltip-ca-viewsource": "ई पन्ना सुरक्षित कइल गइल बा। आप एकर स्रोत देख सकत बानी।",
"tooltip-ca-history": "ए पन्ना के पछिला संशोधन",
- "tooltip-ca-protect": "à¤\87 पनà¥\8dना à¤\95à¥\87 सà¤\82रà¤\95à¥\8dषित à¤\95रà¥\80à¤\82।",
+ "tooltip-ca-protect": "à¤\88 पनà¥\8dना सà¥\81रà¤\95à¥\8dषित à¤\95रà¥\80à¤\82",
"tooltip-ca-unprotect": "ई पन्ना के सुरक्षा बदलीं।",
"tooltip-ca-delete": "ई पन्ना मिटाईं",
"tooltip-ca-move": "एह पन्ना के स्थानांतरण करीं",
"customcssprotected": "No teniu permisos per editar la pàgina CSS perquè conté els paràmetres personals d'un altre usuari.",
"customjsprotected": "No teniu permisos per editar la pàgina JavaScript perquè conté els paràmetres personals d'un altre usuari.",
"mycustomcssprotected": "No tens permís per editar aquesta pàgina CSS.",
+ "mycustomjsonprotected": "No teniu permisos per editar aquesta pàgina JSON.",
"mycustomjsprotected": "No tens permís per editar aquesta pàgina JavaScript.",
"myprivateinfoprotected": "No tens permís per editar la teva informació privada.",
"mypreferencesprotected": "No tens permís per editar les teves preferències.",
"deadendpages": "Pàgines atzucac",
"deadendpagestext": "Aquestes pàgines no tenen enllaços a altres pàgines del projecte {{SITENAME}}.",
"protectedpages": "Pàgines protegides",
+ "protectedpages-filters": "Filtres:",
"protectedpages-indef": "Només proteccions indefinides",
"protectedpages-summary": "Aquesta pàgina llista les pàgines existents que estan protegides actualment. Per a consultar la llista de títols protegits perquè no puguin crear-se'n pàgines, vegeu [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]].",
"protectedpages-cascade": "Només proteccions en cascada",
"apisandbox-dynamic-parameters-add-placeholder": "Nom del paràmetre",
"apisandbox-dynamic-error-exists": "Ja existeix un paràmetre anomenat \"$1\".",
"apisandbox-deprecated-parameters": "Paràmetres obsolets",
+ "apisandbox-add-multi": "Afegeix",
"apisandbox-submit-invalid-fields-title": "Alguns camps no són vàlids",
"apisandbox-submit-invalid-fields-message": "Corregiu els camps marcats i torneu-ho a provar.",
"apisandbox-results": "Resultats",
"filedelete-archive-read-only": "El directori d'arxiu «$1» no té permisos d'escriptura per al servidor web.",
"previousdiff": "← Edició anterior",
"nextdiff": "Edició següent →",
- "mediawarning": "'''Advertència''': Aquest fitxer podria contenir codi maliciós.\nSi l'executeu, podeu comprometre la seguretat del vostre sistema.",
+ "mediawarning": "<strong>Advertiment</strong>: aquest fitxer podria contenir codi maliciós.\nSi l’executeu, podeu comprometre la seguretat del vostre sistema.",
"imagemaxsize": "Límit de mida d'imatges:<br />''(per a pàgines de descripció de fitxers)''",
"thumbsize": "Mida de la miniatura:",
"widthheight": "$1 × $2",
"version-specialpages": "Pàgines especials",
"version-parserhooks": "Extensions de l'analitzador",
"version-variables": "Variables",
+ "version-editors": "Editors",
"version-antispam": "Prevenció spam",
"version-other": "Altres",
"version-mediahandlers": "Connectors multimèdia",
"mytalk": "Сан дийцаре агӀо",
"anontalk": "Дийцаре",
"navigation": "Навигаци",
- "and": " а",
+ "and": ",",
"faq": "СиХХ",
"actions": "Дийраш",
"namespaces": "ЦӀерийн меттигаш",
"extlink_tip": "Арахьара хьажорг (йиц ма йе хӀотталушерг http://)",
"headline_sample": "Йозан корта",
"headline_tip": "Корта 2-гlа локхаллийца",
- "nowiki_sample": "ЧÑ\83диллийÑ\88а кÑ\85Ñ\83зе баÑ\80амÑ\85lоÑ\82Ñ\82онза йоза.",
+ "nowiki_sample": "Ð\9aÑ\85Ñ\83за Ñ\85Ó\80оÑ\82Ñ\82аде Ñ\85ийÑ\86а оÑ\8cÑ\88Ñ\83Ñ\88 доÑ\86Ñ\83 йоза",
"nowiki_tip": "Тергал ца бо вики-бáрамхlоттор",
"image_sample": "Example.jpg",
"image_tip": "Чохь йолу файл",
"rcfilters-clear-all-filters": "Ерриге литтарш цӀанъян",
"rcfilters-show-new-changes": "ТӀеххьара хийцамаш",
"rcfilters-search-placeholder": "Литтаран керла хийцамаш лахар",
+ "rcfilters-empty-filter": "Жигара литтарш дац. Дерриге нисдарш гойтуш ю.",
"rcfilters-filterlist-title": "Литтарш",
"rcfilters-filterlist-feedbacklink": "Керла (бета) литтарех лаьцна хьайна хеттарг язде",
"rcfilters-highlightbutton-title": "Билгалде карийнарш",
"boteditletter": "б",
"number_of_watching_users_pageview": "[$1 {{PLURAL:$1|тӀехьожу декъашхо|тӀехьожу декъашхой}}]",
"rc-change-size-new": "Хийцам бин чул тӀехьа болу барам: $1 {{PLURAL:$1|байт}}",
- "newsectionsummary": "/* $1 */ Ð\9aеÑ\80ла Ñ\85Ñ\8cедаÑ\80",
+ "newsectionsummary": "/* $1 */ Ð\9aеÑ\80ла Ñ\82ема",
"rc-enhanced-expand": "Гайта мадарра",
"rc-enhanced-hide": "Ма дарра дерг къайладаккха",
"rc-old-title": "дуьххьара кхоьллина яра «$1» цӀарца",
"apisandbox-continue-help": "{{int:apisandbox-continue}} [https://www.mediawiki.org/wiki/API:Query#Continuing_queries чекхдаккха] тӀеххьара дехар; {{int:apisandbox-continue-clear}} чекхдаккхарца йолу параметраш цӀанъян.",
"apisandbox-multivalue-all-namespaces": "$1 (Ерриге цӀерийн меттигаш)",
"apisandbox-multivalue-all-values": "$1 (Дерриге маьӀнаш)",
- "booksources": "Ð\96айнан хьосташ",
+ "booksources": "Ð\96айнийн хьосташ",
"booksources-search-legend": "Жайнех лаьцна хаам лахар",
"booksources-search": "Лахар",
"booksources-text": "ХӀокху агӀонгахь гул бина сайтийн тӀе хьажоргийн могӀам оцу чохь шуна жайнах лаьцна хаам каро мега. И ю интернет-туьканаш а категорийн библиотекийн категорешкахь лахаран система а.",
"confirm-unwatch-top": "ДӀаяккха хӀара агӀо хьай тергаме могӀанан юкъар?",
"confirm-rollback-button": "ХӀаъ",
"confirm-rollback-top": "ХӀокху агӀона нисдарш юхадаха?",
- "comma-separator": " a, ",
+ "comma-separator": ", ",
"quotation-marks": "«$1»",
"imgmultipageprev": "← хьалха йоьду агӀо",
"imgmultipagenext": "тӀаьхьа йоьгӀу агӀо →",
"change-blocklink": "změnit blok",
"contribslink": "příspěvky",
"emaillink": "poslat e-mail",
- "autoblocker": "Automatické zablokování kvůli tomu, že vaši IP adresu nedávno {{GENDER:$1|používal uživatel|používala uživatelka}} „[[User:$1|$1]]“.\nDůvod zablokování {{GENDER:$1|uživatele $1|uživatelky $1}}: „$2“",
+ "autoblocker": "Automatické zablokování kvůli tomu, že vaši IP adresu nedávno používal uživatel „[[User:$1|$1]]“.\nDůvod zablokování uživatele $1: „$2“",
"blocklogpage": "Kniha zablokování",
"blocklog-showlog": "{{GENDER:$1|Tento uživatel byl dříve blokován.|Tato uživatelka byla dříve blokována.|Tento uživatel byl dříve blokován.}}\nZde je pro přehled zobrazen výpis z knihy zablokování:",
"blocklog-showsuppresslog": "{{GENDER:$1|Tento uživatel byl zablokován a skryt|Tato uživatelka byla zablokována a skryta}}. Zde je pro přehled zobrazen výpis záznamu utajení:",
"tog-hidepatrolled": "Kontrollierte Änderungen in den „Letzten Änderungen“ ausblenden",
"tog-newpageshidepatrolled": "Kontrollierte Seiten bei den „Neuen Seiten“ ausblenden",
"tog-hidecategorization": "Kategorisierungen von Seiten ausblenden",
- "tog-extendwatchlist": "Alle und nicht nur die aktuellsten Änderungen in der Beobachtungsliste anzeigen",
+ "tog-extendwatchlist": "Alle Änderungen in der Beobachtungsliste anzeigen, nicht nur die aktuellsten",
"tog-usenewrc": "Änderungen auf „Letzte Änderungen“ und der Beobachtungsliste nach Seite gruppieren",
"tog-numberheadings": "Überschriften automatisch nummerieren",
"tog-showtoolbar": "Bearbeiten-Werkzeugleiste anzeigen",
"recentchangeslinked-feed": "Änderungen an verlinkten Seiten",
"recentchangeslinked-toolbox": "Änderungen an verlinkten Seiten",
"recentchangeslinked-title": "Änderungen an Seiten, die von „$1“ verlinkt sind",
- "recentchangeslinked-summary": "Gib einen Seitennamen ein, um Änderungen auf Seiten zu sehen, die auf oder von dieser Seite verlinkt sind. Um Mitglieder einer Kategorie zu sehen, gib „Kategorie:''Name der Kategorie''“ ein. Änderungen an Seiten auf [[Special:Watchlist|deiner Beobachtungsliste]] sind <strong>fett</strong> hervorgehoben.",
+ "recentchangeslinked-summary": "Gib einen Seitennamen ein, um Änderungen auf Seiten zu sehen, die auf oder von dieser Seite verlinkt sind. Um Mitglieder einer Kategorie zu sehen, gib „{{ns:category}}:''Name der Kategorie''“ ein. Änderungen an Seiten auf [[Special:Watchlist|deiner Beobachtungsliste]] sind <strong>fett</strong> hervorgehoben.",
"recentchangeslinked-page": "Seite:",
"recentchangeslinked-to": "Zeige nur Änderungen an Seiten, die auf diese Seite verlinken",
"recentchanges-page-added-to-category": "[[:$1]] zur Kategorie hinzugefügt",
"apisandbox": "API qumdor",
"apisandbox-submit": "Bıwazê",
"apisandbox-reset": "Bestere",
- "apisandbox-retry": "Fına",
+ "apisandbox-retry": "Anciya bıcerrebne",
"apisandbox-examples": "Misali",
"apisandbox-dynamic-parameters": "Parametreya debyayi",
"apisandbox-dynamic-parameters-add-label": "Parametre dek:",
"rcfilters-watchlist-showupdated": "Σελίδες που έχουν υποστεί αλλαγές από την τελευταία φορά που τις επισκεφθήκατε εμφανίζονται με '''έντονους χαρακτήρες'''.",
"rcfilters-preference-label": "Απόκρυψη της βελτιωμένης έκδοσης των Πρόσφατων Αλλαγών",
"rcfilters-preference-help": "Αναστέλλει τον επανασχεδιασμό διεπαφής 2017 και όλα τα εργαλεία που προστέθηκαν στη συνέχεια και από τότε.",
+ "rcfilters-filter-showlinkedfrom-option-label": "<strong>Σελίδες που συνδέονται από</strong> τη επιλεγμένη σελίδα",
+ "rcfilters-filter-showlinkedto-label": "Εμφάνιση αλλαγών σε σελίδες που συνδέουν σε",
+ "rcfilters-target-page-placeholder": "Εισαγάγετε όνομα σελίδας (ή κατηγορίας)",
"rcnotefrom": "Παρακάτω {{PLURAL:$5|είναι η αλλαγή|είναι οι αλλαγές}} από <strong>$3, $4</strong> (έως <strong>$1</strong> που εμφανίζεται).",
+ "rclistfromreset": "Επαναφορά ρύθμισης ημερομηνίας",
"rclistfrom": "Εμφάνιση νέων αλλαγών αρχίζοντας από τις $3 στις $2",
"rcshowhideminor": "$1 μικροεπεξεργασιών",
"rcshowhideminor-show": "Εμφάνιση",
"pageswithprop-legend": "Σελίδες με ιδιότητα σελίδας",
"pageswithprop-text": "Αυτή η σελίδα ταξινομεί σελίδες που χρησιμοποιούν μια συγκεκριμένη ιδιότητα σελίδας.",
"pageswithprop-prop": "Όνομα ιδιότητας:",
+ "pageswithprop-reverse": "Ταξινόμηση σε αντίστροφη σειρά",
+ "pageswithprop-sortbyvalue": "Ταξινόμηση ανά τιμή ιδιότητας",
"pageswithprop-submit": "Μετάβαση",
"pageswithprop-prophidden-long": "τιμή ιδιότητας μακρού κειμένου κρυμμένη ($1)",
"pageswithprop-prophidden-binary": "τιμή ιδιότητας δυαδικών δεδομένων κρυμμένη ($1)",
"log-action-filter-contentmodel-new": "Δημιουργία σελίδας με μη προεπιλεγμένο μοντέλο περιεχομένου",
"log-action-filter-delete-delete": "Διαγραφή σελίδας",
"log-action-filter-delete-restore": "Ξεδιαγραφή σελίδας",
+ "log-action-filter-delete-event": "Διαγραφή μητρώου",
+ "log-action-filter-delete-revision": "Διαγραφή αναθεώρησης",
"log-action-filter-import-interwiki": "Εισαγωγή Transwiki",
"log-action-filter-import-upload": "Εισαγωγή μέσω ανεβάσματος XML",
"log-action-filter-managetags-create": "Δημιουργία ετικέτας",
"log-action-filter-managetags-delete": "Διαγραφή ετικέττας",
+ "log-action-filter-managetags-activate": "Ενεργοποίηση ετικέτας",
+ "log-action-filter-managetags-deactivate": "Απενεργοποίηση ετικέτας",
+ "log-action-filter-newusers-create": "Δημιουργία από ανώνυμο χρήστη",
+ "log-action-filter-newusers-create2": "Δημιουργία από εγγεγραμμένο χρήστη",
"log-action-filter-newusers-autocreate": "Αυτόματη δημιουργία",
"log-action-filter-patrol-patrol": "Χειροκίνητη περιπολία",
"log-action-filter-patrol-autopatrol": "Αυτόματη περιπολία",
"log-action-filter-protect-move_prot": "Μετακίνηση προστασίας",
"log-action-filter-rights-rights": "Χειροκίνητη αλλαγή",
"log-action-filter-rights-autopromote": "Αυτόματη αλλαγή",
+ "log-action-filter-suppress-event": "Καταστολή μητρώου",
+ "log-action-filter-suppress-revision": "Καταστολή αναθεώρησης",
+ "log-action-filter-suppress-delete": "Καταστολή σελίδας",
"log-action-filter-upload-upload": "Νέα μεταφόρτωση",
"log-action-filter-upload-overwrite": "Επαναμεταφόρτωση",
"authmanager-create-disabled": "Η δημιουργία λογαριασμού έχει απενεργοποιηθεί.",
"changecredentials-submit": "Αλλαγή πιστοποιητικών",
"removecredentials": "Αφαίρεση πιστοποιητικών",
"removecredentials-submit": "Αφαίρεση πιστοποιητικών",
+ "credentialsform-provider": "Τύπος πιστοποιητικών:",
"credentialsform-account": "Όνομα λογαριασμού:",
"cannotlink-no-provider-title": "Δεν υπάρχουν συνδέσιμοι λογαριασμοί",
"cannotlink-no-provider": "Δεν υπάρχουν συνδέσιμοι λογαριασμοί.",
"recentchangeslinked-feed": "Related changes",
"recentchangeslinked-toolbox": "Related changes",
"recentchangeslinked-title": "Changes related to \"$1\"",
- "recentchangeslinked-summary": "Enter a page name to see changes on pages linked to or from that page. (To see members of a category, enter Category:Name of category). Changes to pages on [[Special:Watchlist|your Watchlist]] are in <strong>bold</strong>.",
+ "recentchangeslinked-summary": "Enter a page name to see changes on pages linked to or from that page. (To see members of a category, enter {{ns:category}}:Name of category). Changes to pages on [[Special:Watchlist|your Watchlist]] are in <strong>bold</strong>.",
"recentchangeslinked-page": "Page name:",
"recentchangeslinked-to": "Show changes to pages linked to the given page instead",
"recentchanges-page-added-to-category": "[[:$1]] added to category",
"autoredircomment": "Alidirektigis al [[$1]]",
"autosumm-new": "Nova paĝo kun '$1'",
"autosumm-newblank": "Kreis nulan paĝon",
+ "size-bytes": "$1 {{PLURAL:$1|bajto|bajtoj}}",
"lag-warn-normal": "Ŝanĝoj pli novaj ol $1 {{PLURAL:$1|sekundo|sekundoj}} eble ne estos montrataj en ĉi tiu listo.",
"lag-warn-high": "Pro malrapideco de la servila datumbazo, ŝanĝoj pli novaj ol $1 {{PLURAL:$1|sekundo|sekundoj}} eble ne montriĝos en ĉi tiu listo.",
"watchlistedit-normal-title": "Redakti atentaron",
"changepassword-throttled": "Has intentado acceder demasiadas veces recientemente.\nEspera $1 antes de intentarlo de nuevo.",
"botpasswords": "Contraseñas de bots",
"botpasswords-summary": "Las <em>contraseñas de bots</em> permiten el acceso a una cuenta de usuario mediante la API sin usar las credenciales principales de la cuenta. Los derechos de un usuario mientras haya iniciado sesión con una contraseña de bot pueden estar restringidos.\n\nSi no sabes por qué querrías hacer esto, probablemente no deberías hacerlo. Nadie debería pedirte que generes una de estas claves y que se la entregues.",
- "botpasswords-disabled": "Las contraseñas de bot están desactivadas.",
+ "botpasswords-disabled": "Las contraseñas de robot están desactivadas.",
"botpasswords-no-central-id": "Para usar una contraseña de bot, debes estar conectado a una cuenta centralizada.",
"botpasswords-existing": "Contraseñas de bots existentes",
- "botpasswords-createnew": "Crear una nueva contraseña de bot",
- "botpasswords-editexisting": "Editar una contraseña de bot existente",
- "botpasswords-label-appid": "Nombre del bot:",
+ "botpasswords-createnew": "Crear una contraseña de robot nueva",
+ "botpasswords-editexisting": "Editar una contraseña de robot existente",
+ "botpasswords-label-appid": "Nombre del robot:",
"botpasswords-label-create": "Crear",
"botpasswords-label-update": "Actualizar",
"botpasswords-label-cancel": "Cancelar",
"botpasswords-label-grants": "Permisos aplicables:",
"botpasswords-help-grants": "Cada concesión le da acceso a los permisos listados que el usuario ya posea. Habilitar una concesión aquí no proporciona acceso a ningún permiso que tu cuenta de usuario no tendría de otra manera. Véase la [[Special:ListGrants|lista de concesiones]] para más información.",
"botpasswords-label-grants-column": "Concedido",
- "botpasswords-bad-appid": "El nombre del bot \"$1\" no es válido.",
+ "botpasswords-bad-appid": "El nombre del robot «$1» no es válido.",
"botpasswords-insert-failed": "No se pudo agregar el nombre del bot \"$1\". ¿Ya ha sido añadido?",
"botpasswords-update-failed": "No se pudo actualizar el nombre del bot \"$1\". ¿Ha sido borrado?",
- "botpasswords-created-title": "Se creó la contraseña de bot",
+ "botpasswords-created-title": "Se creó la contraseña de robot",
"botpasswords-created-body": "Se creó la contraseña del robot «$1» perteneciente {{GENDER:$2|al usuario|a la usuaria}} «$2».",
- "botpasswords-updated-title": "Se actualizó la contraseña de bot",
+ "botpasswords-updated-title": "Se actualizó la contraseña de robot",
"botpasswords-updated-body": "Se actualizó la contraseña del robot «$1» perteneciente {{GENDER:$2|al usuario|a la usuaria}} «$2».",
- "botpasswords-deleted-title": "Se eliminó la contraseña de bot",
+ "botpasswords-deleted-title": "Se eliminó la contraseña de robot",
"botpasswords-deleted-body": "Se eliminó la contraseña del robot «$1» perteneciente {{GENDER:$2|al usuario|a la usuaria}} «$2».",
"botpasswords-newpassword": "La contraseña nueva para acceder con <strong>$1</strong> es <strong>$2</strong>. <em>Guarda esta información para su consulta futura.</em> <br> (En caso de robots antiguos que requieren que el nombre de acceso coincida con el de usuario, también puedes utilizar <strong>$3</strong> como nombre de usuario y <strong>$4</strong> como contraseña.)",
"botpasswords-no-provider": "BotPasswordsSessionProvider no está disponible.",
"group": "Grupo:",
"group-user": "Usuarios",
"group-autoconfirmed": "Autoconfirmados",
- "group-bot": "Bots",
+ "group-bot": "Robots",
"group-sysop": "Administradores",
"group-bureaucrat": "Burócratas",
"group-suppress": "Supresores de Flow",
"group-all": "(todos)",
"group-user-member": "{{GENDER:$1|usuario|usuaria}}",
"group-autoconfirmed-member": "{{GENDER:$1|autoconfirmado|autoconfirmada}}",
- "group-bot-member": "{{GENDER:$1|bot}}",
+ "group-bot-member": "{{GENDER:$1|robot}}",
"group-sysop-member": "{{GENDER:$1|administrador|administradora}}",
"group-bureaucrat-member": "{{GENDER:$1|burócrata}}",
"group-suppress-member": "{{GENDER:$1|supresor|supresora}} de Flow",
"grouppage-user": "{{ns:project}}:Usuarios",
"grouppage-autoconfirmed": "{{ns:project}}:Autoconfirmados",
- "grouppage-bot": "{{ns:project}}:Bots",
+ "grouppage-bot": "{{ns:project}}:Robots",
"grouppage-sysop": "{{ns:project}}:Administradores",
"grouppage-bureaucrat": "{{ns:project}}:Burócratas",
"grouppage-suppress": "{{ns:project}}:Supresores de Flow",
"right-editmyprivateinfo": "Editar su propia información privada (ej.: correo electrónico, nombre real)",
"right-editmyoptions": "Editar tus preferencias",
"right-rollback": "Revertir rápidamente las ediciones del último usuario que modificó una página en particular",
- "right-markbotedits": "Marcar ediciones revertidas como ediciones de bot",
+ "right-markbotedits": "Marcar las reversiones como ediciones de robot",
"right-noratelimit": "No resultar afectado por los límites de frecuencia de edición",
"right-import": "Importar páginas desde otras wikis",
"right-importupload": "Importar páginas desde un archivo",
"rcfilters-filter-user-experience-level-experienced-label": "Usuarios experimentados",
"rcfilters-filter-user-experience-level-experienced-description": "Editores registrados con más de 500 ediciones y 30 días de actividad.",
"rcfilters-filtergroup-automated": "Contribuciones automatizadas",
- "rcfilters-filter-bots-label": "Bot",
+ "rcfilters-filter-bots-label": "Robot",
"rcfilters-filter-bots-description": "Ediciones realizadas por herramientas automatizadas.",
- "rcfilters-filter-humans-label": "Ser humano (no bot)",
+ "rcfilters-filter-humans-label": "Ser humano (no robot)",
"rcfilters-filter-humans-description": "Ediciones realizadas por editores humanos.",
"rcfilters-filtergroup-reviewstatus": "Estado de revisión",
"rcfilters-filter-reviewstatus-unpatrolled-label": "No patrulladas",
"rcfilters-filter-reviewstatus-manual-label": "Verificado manualmente",
- "rcfilters-filter-reviewstatus-auto-description": "Ediciones por usuarios avanzadus cuyo trabajo es marcado automáticamente como verificado.",
+ "rcfilters-filter-reviewstatus-auto-description": "Ediciones por usuarios avanzados cuyo trabajo se marca automáticamente como verificado.",
"rcfilters-filter-reviewstatus-auto-label": "Autoverificado",
"rcfilters-filtergroup-significance": "Significación",
"rcfilters-filter-minor-label": "Ediciones menores",
"import-upload-username-prefix": "Prefijo de interwiki:",
"import-assign-known-users": "Asignar ediciones a usuarios locales cuando el usuario correspondiente exista localmente",
"import-comment": "Comentario:",
- "importtext": "Por favor, exporta el archivo desde el wiki de origen usando la [[Special:Export|herramienta de exportación]], guárdalo en tu disco y súbelo aquí.",
+ "importtext": "Exporta el archivo desde el wiki de origen mediante la [[Special:Export|herramienta de exportación]], guárdalo en tu disco y cárgalo aquí.",
"importstart": "Importando páginas...",
"import-revision-count": "$1 {{PLURAL:$1|revisión|revisiones}}",
"importnopages": "No hay páginas que importar.",
"noscript.css": "/* Los estilos CSS colocados aquí se aplicarán a los usuarios que hayan desactivado el JavaScript en su navegador */",
"group-autoconfirmed.css": "/* Los estilos CSS colocados aquí se aplicarán para todos los usuarios del grupo Usuarios autoconfirmados */",
"group-user.css": "/* Los estilos CSS colocados aquí se aplicarán para todos los usuarios registrados */",
- "group-bot.css": "/* Los estilos CSS colocados aquí se aplicarán para todos los usuarios del grupo Bots */",
+ "group-bot.css": "/* Los estilos CSS colocados aquí se aplicarán para todos los usuarios del grupo Robots */",
"group-sysop.css": "/* Los estilos CSS colocados aquí se aplicarán para todos los usuarios del grupo Administradores */",
"group-bureaucrat.css": "/* Los estilos CSS colocados aquí se aplicarán para todos los usuarios del grupo Burócratas */",
"common.js": "/* Cualquier código JavaScript escrito aquí se cargará para todos los usuarios en cada carga de página */",
"group-autoconfirmed.js": "/* Cualquier código JavaScript escrito aquí se cargará para todos los usuarios del grupo Usuarios autoconfirmados */",
"group-user.js": "/* Cualquier código JavaScript escrito aquí se cargará para todos los usuarios registrados */",
- "group-bot.js": "/* Cualquier código JavaScript escrito aquí se cargará para todos los usuarios del grupo Bots */",
+ "group-bot.js": "/* Cualquier código JavaScript escrito aquí se cargará para todos los usuarios del grupo Robots */",
"group-sysop.js": "/* Cualquier código JavaScript escrito aquí se cargará para todos los usuarios del grupo Administradores */",
"group-bureaucrat.js": "/* Cualquier código JavaScript escrito aquí se cargará para todos los usuarios del grupo Burócratas */",
"anonymous": "{{PLURAL:$1|Usuario anónimo|Usuarios anónimos}} de {{SITENAME}}",
"filedelete-archive-read-only": "El servidor web no logra escribir en el directorio archivo \"$1\".",
"previousdiff": "← Edición anterior",
"nextdiff": "Edición siguiente →",
- "mediawarning": "<strong>Advertencia:</strong> este archivo puede contener código malicioso.\nEjecutarlo podría comprometer la seguridad de tu equipo.",
+ "mediawarning": "<strong>Atención:</strong> este archivo puede contener código malicioso.\nEjecutarlo podría comprometer la seguridad de tu equipo.",
"imagemaxsize": "Límite de tamaño de imagen:<br />''(para páginas de descripción de archivo)''",
"thumbsize": "Tamaño de las vistas en miniatura:",
"widthheight": "$1 × $2",
"tog-watchlisthideminor": "Peida pisiparandused jälgimisloendist",
"tog-watchlisthideliu": "Peida sisselogitud kasutajate muudatused jälgimisloendist",
"tog-watchlistreloadautomatically": "Laadi jälgimisloend mõne filtri muutmise järel koheselt uuesti (nõutav JavaScript)",
- "tog-watchlistunwatchlinks": "Lisa jälgimisloendi sissekannete juurde jälgimisest loobumise või jälgimise otselingid (tumblerfunktsiooni jaoks nõutav JavaScript)",
+ "tog-watchlistunwatchlinks": "Lisa muudatuse juurde otselingid ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}), et jälgimisest loobuda või loobumine tagasi võtta (tumblerfunktsiooni jaoks nõutav JavaScript)",
"tog-watchlisthideanons": "Peida anonüümsete kasutajate muudatused jälgimisloendist",
"tog-watchlisthidepatrolled": "Peida kontrollitud muudatused jälgimisloendist",
"tog-watchlisthidecategorization": "Peida lehekülgede kategoriseerimine",
"password-login-forbidden": "Selle kasutajanime ja parooli kasutamine on keelatud.",
"mailmypassword": "Lähtesta parool",
"passwordremindertitle": "{{SITENAME}} – ajutine parool",
- "passwordremindertext": "Keegi IP-aadressiga $1, tõenäoliselt sa ise, palus, et talle\nsaadetaks {{GRAMMAR:elative|{{SITENAME}}}} uus parool ($4).\nKasutaja \"$2\" ajutiseks paroolis seati \"$3\". Kui soovid tõepoolest\nuut parooli, pead sisse logima ja uue parooli valima.\nAjutine parool aegub {{PLURAL:$5|ühe|$5}} päeva pärast.\n\nKui uut parooli palus keegi teine või sulle meenus vana parool\nja sa ei soovi seda enam muuta, võid seda teadet eirata ning\njätkata senise parooli kasutamist.",
+ "passwordremindertext": "Keegi IP-aadressiga $1 palus, et talle\nsaadetaks {{GRAMMAR:elative|{{SITENAME}}}} uus parool ($4).\nKasutaja \"$2\" ajutiseks paroolis seati \"$3\". Kui soovid tõepoolest\nuut parooli, pead sisse logima ja uue parooli valima.\nAjutine parool aegub {{PLURAL:$5|ühe|$5}} päeva pärast.\n\nKui uut parooli palus keegi teine või sulle meenus vana parool\nja sa ei soovi seda enam muuta, võid seda teadet eirata ning\njätkata senise parooli kasutamist.",
"noemail": "Kasutaja $1 e-posti aadressi meil kahjuks pole.",
"noemailcreate": "Pead sisestama korrektse e-posti aadressi",
"passwordsent": "Uus parool on saadetud kasutaja $1 registreeritud e-postiaadressil.\nPärast parooli saamist logige palun sisse.",
"longpageerror": "'''Tõrge: Lehekülge ei saa salvestada, sest sinu esitatud {{PLURAL:$1|ühe|$1}} kilobaidi suurune tekst ületab {{PLURAL:$2|ühekilobaidist|$2-kilobaidist}} ülemmäära.'''",
"readonlywarning": "<strong>Hoiatus: Andmebaas on lukustatud hooldustöödeks, nii et praegu ei saa parandusi salvestada.</strong>\nVõid teksti hilisemaks kasutamiseks alles hoida tekstifailina.\n\nSüsteemiadministraator, kes andmebaasi lukustas, andis järgmise selgituse: $1",
"protectedpagewarning": "'''Hoiatus: See lehekülg on lukustatud, nii et ainult administraatori õigustega kasutajad saavad seda redigeerida.'''\nAllpool on toodud uusim logisissekanne:",
- "semiprotectedpagewarning": "'''Märkus:''' See lehekülg on lukustatud, nii et üksnes registreeritud kasutajad saavad seda muuta.\nAllpool on toodud uusim logisissekanne:",
+ "semiprotectedpagewarning": "<strong>Märkus:</strong> See lehekülg on lukustatud, nii et üksnes automaatselt kinnitatud kasutajad saavad seda muuta.\nAllpool on toodud uusim logisissekanne:",
"cascadeprotectedwarning": "<strong>Hoiatus:</strong> See lehekülg on nii kaitstud, et ainult [[Special:ListGroupRights|teatud õigustega]] kasutajad saavad seda redigeerida, sest lehekülg on osa {{PLURAL:$1|järgmisest|järgmistest}} kaskaadkaitsega {{PLURAL:$1|leheküljest|lehekülgedest}}:",
"titleprotectedwarning": "'''Hoiatus: See lehekülg on nii lukustatud, et selle loomiseks on tarvis [[Special:ListGroupRights|eriõigusi]].'''\nAllpool on toodud uusim logisissekanne:",
"templatesused": "Sellel leheküljel on kasutusel {{PLURAL:$1|järgmine mall|järgmised mallid}}:",
"suppressionlogtext": "Allpool on nimekiri kustutamistest ja blokeeringutest, millega kaasneb administraatorite eest sisu varjamine.\nJõus olevad keelud ja blokeeringud leiad [[Special:BlockList|blokeerimisnimekirja]].",
"mergehistory": "Lehekülgede ajalugude liitmine",
"mergehistory-header": "Siin leheküljel saad ühe lehekülje ajaloo redaktsioonid uuema leheküljega liita.\nVeendu, et selle muudatusega jääb lehekülje redigeerimislugu ajaliselt katkematuks.",
- "mergehistory-box": "Kahe lehekülje redaktsioonide liitmine:",
+ "mergehistory-box": "Kahe lehekülje redaktsioonide liitmine",
"mergehistory-from": "Alliklehekülg:",
"mergehistory-into": "Sihtlehekülg:",
"mergehistory-list": "Liidetav redigeerimise ajalugu",
"prefs-dateformat": "Kuupäeva vorming",
"prefs-timeoffset": "Ajavahe",
"prefs-advancedediting": "Üldsuvandid",
+ "prefs-developertools": "Arendusriistad",
"prefs-editor": "Toimeti",
"prefs-preview": "Eelvaade",
"prefs-advancedrc": "Täpsemad eelistused",
"rcfilters-filter-humans-label": "Pole robot",
"rcfilters-filter-humans-description": "Vahetult inimese tehtud muudatused.",
"rcfilters-filtergroup-reviewstatus": "Ülevaatuse seis",
+ "rcfilters-filter-reviewstatus-unpatrolled-description": "Muudatused, mida pole käsitsi ega automaatselt kontrollituks märgitud.",
"rcfilters-filter-reviewstatus-unpatrolled-label": "Kontrollimata",
+ "rcfilters-filter-reviewstatus-manual-description": "Käsitsi kontrollituks märgitud muudatused.",
+ "rcfilters-filter-reviewstatus-manual-label": "Käsitsi kontrollitud",
+ "rcfilters-filter-reviewstatus-auto-description": "Muudatused, mille on teinud eriõigusega kasutajad, kelle kaastöö märgitakse automaatselt kontrollituks.",
+ "rcfilters-filter-reviewstatus-auto-label": "Automaatselt kontrollitud",
"rcfilters-filtergroup-significance": "Olulisus",
"rcfilters-filter-minor-label": "Pisimuudatused",
"rcfilters-filter-minor-description": "Muudatused, mille autor märkis pisimuudatuseks.",
"deadendpages": "Edasipääsuta leheküljed",
"deadendpagestext": "Järgmised leheküljed ei viita ühelegi teisele {{GRAMMAR:genitive|{{SITENAME}}}} leheküljele.",
"protectedpages": "Kaitstud leheküljed",
+ "protectedpages-filters": "Filtrid:",
"protectedpages-indef": "Ainult määramata ajani kaitstud",
"protectedpages-summary": "Siin on loetletud olemasolevad leheküljed, mis on praegu kaitstud. Loomise eest kaitstud pealkirjade loendi leiad [[{{#special:ProtectedTitles}}|siit]].",
"protectedpages-cascade": "Ainult kaskaadkaitsega",
"apisandbox-dynamic-error-exists": "Parameeter nimega \"$1\" on juba olemas.",
"apisandbox-deprecated-parameters": "Vananenud parameetrid",
"apisandbox-fetch-token": "Hangi luba automaatselt",
+ "apisandbox-add-multi": "Lisa",
"apisandbox-submit-invalid-fields-title": "Mõned väljad on vigased",
"apisandbox-submit-invalid-fields-message": "Palun paranda märgitud väljad ja proovi uuesti.",
"apisandbox-results": "Tulemused",
"fix-double-redirects": "Värskenda kõik siia viitavad ümbersuunamislehed uuele pealkirjale",
"move-leave-redirect": "Jäta maha ümbersuunamisleht",
"protectedpagemovewarning": "'''Hoiatus:''' See lehekülg on nii lukustatud, et ainult administraatori õigustega kasutajad saavad seda teisaldada.\nAllpool on toodud uusim logisissekanne:",
- "semiprotectedpagemovewarning": "'''Pane tähele:''' See lehekülg on lukustatud, nii et ainult registreeritud kasutajad saavad seda teisaldada.\nAllpool on toodud uusim logisissekanne:",
+ "semiprotectedpagemovewarning": "<strong>Pane tähele:</strong> See lehekülg on lukustatud, nii et ainult automaatselt kinnitatud kasutajad saavad seda teisaldada.\nAllpool on toodud uusim logisissekanne:",
"move-over-sharedrepo": "[[:$1]] on olemas jagatud failivaramus. Faili teisaldamisel selle nime alla varjatakse jagatud failivarmus olev samanimeline fail.",
"file-exists-sharedrepo": "Valitud failinimi on juba kasutusel jagatud failivaramus.\nPalun kasuta mõnda teist nime.",
"export": "Lehekülgede eksport",
"version-specialpages": "Erileheküljed",
"version-parserhooks": "Parserihaagid",
"version-variables": "Muutujad",
+ "version-editors": "Toimetid",
"version-antispam": "Rämpsposti tõkestus",
"version-other": "Muu",
"version-mediahandlers": "Meediatöötlejad",
"savechanges": "Aldaketak gorde",
"publishpage": "Orrialdea argitaratu",
"publishchanges": "Aldaketak argitaratu",
+ "savechanges-start": "Aldaketak gorde...",
+ "publishpage-start": "Orrialdea argitaratu...",
+ "publishchanges-start": "Aldaketak argitaratu...",
"preview": "Aurrebista erakutsi",
"showpreview": "Aurrebista erakutsi",
"showdiff": "Aldaketak erakutsi",
"prefs-dateformat": "Data-formatua",
"prefs-timeoffset": "Denbora ezberdintasuna",
"prefs-advancedediting": "Genero aukerak",
+ "prefs-developertools": "Garatzaile tresnak",
"prefs-editor": "Editorea",
"prefs-preview": "Aurreikusi",
"prefs-advancedrc": "Aukera aurreratuak",
"rcfilters-filter-humans-description": "Gizaki editoreek egindako aldaketak.",
"rcfilters-filtergroup-reviewstatus": "Berrikuspenaren egoera",
"rcfilters-filter-reviewstatus-unpatrolled-label": "Patruilagabea",
+ "rcfilters-filter-reviewstatus-manual-label": "Eskuz patruilatuak",
"rcfilters-filtergroup-significance": "Munta",
"rcfilters-filter-minor-label": "Aldaketa txikiak",
"rcfilters-filter-minor-description": "Egileak sailkatutako aldaketa txikiak.",
"deadendpages": "Orrialde itsuak",
"deadendpagestext": "Jarraian zerrendatutako orrialdeek ez daukate wikiko beste edozein orrialdetarako loturarik.",
"protectedpages": "Babestutako orrialdeak",
+ "protectedpages-filters": "Iragazkiak:",
"protectedpages-indef": "Babes mugagabeak bakarrik",
"protectedpages-summary": "Orrialde honetan unean babestutako orriak zerrendatzen dira. Sorkuntza babesten duten izenen zerrenda lortzeko, ikusi [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]].",
"protectedpages-cascade": "Kaskada moduko babesak bakarrik",
"apisandbox-dynamic-error-exists": "$1 parametro izena dagoeneko existitzen da",
"apisandbox-deprecated-parameters": "Aurretiaz zehaztutako parametroak",
"apisandbox-fetch-token": "Token-a automatikoki bete",
+ "apisandbox-add-multi": "Gehitu",
"apisandbox-submit-invalid-fields-title": "Zelai batzuk ez dute balio.",
"apisandbox-submit-invalid-fields-message": "Mesedez, zuzendu markatutako zelaiak eta saiatu berrio.",
"apisandbox-results": "Emaitzak",
"version-specialpages": "Aparteko orrialdeak",
"version-parserhooks": "Parser estentsioak",
"version-variables": "Aldagaiak",
+ "version-editors": "Editoreak",
"version-antispam": "Spam ekiditea",
"version-other": "Bestelakoak",
"version-mediahandlers": "Media gordailuak",
"customcssprotected": "Sinulla ei ole oikeutta muuttaa tätä CSS-sivua, koska se sisältää toisen käyttäjän henkilökohtaisia asetuksia.",
"customjsprotected": "Sinulla ei ole oikeutta muuttaa tätä JavaScript-sivua, koska se sisältää toisen käyttäjän henkilökohtaisia asetuksia.",
"mycustomcssprotected": "Sinulla ei ole oikeutta muokata tätä CSS-sivua.",
+ "mycustomjsonprotected": "Sinulla ei ole oikeutta muokata tätä JSON-sivua.",
"mycustomjsprotected": "Sinulla ei ole oikeutta muokata tätä JavaScript-sivua.",
"myprivateinfoprotected": "Sinulla ei ole oikeutta muuttaa omia yksityisiä tietojasi.",
"mypreferencesprotected": "Sinulla ei ole oikeutta muuttaa omia asetuksiasi.",
"rcfilters-filter-humans-label": "Ihminen (ei botti)",
"rcfilters-filter-humans-description": "Ihmisten tekemät muokkaukset.",
"rcfilters-filtergroup-reviewstatus": "Sivun partioinnin status",
+ "rcfilters-filter-reviewstatus-unpatrolled-description": "Muutoksia ei ole merkitty manuaalisesti tai automaattisesti partioiduksi.",
"rcfilters-filter-reviewstatus-unpatrolled-label": "Ei ole partioitu",
+ "rcfilters-filter-reviewstatus-manual-description": "Muutokset merkitty partioiduksi manuaalisesti.",
+ "rcfilters-filter-reviewstatus-manual-label": "Manuaalisesti partioitu",
+ "rcfilters-filter-reviewstatus-auto-description": "Muutokset edistyneiltä käyttäjiltä joiden työ on automaattisesti merkitty partioiduksi.",
+ "rcfilters-filter-reviewstatus-auto-label": "Automaattisesti partioitu",
"rcfilters-filtergroup-significance": "Merkitys",
"rcfilters-filter-minor-label": "Pienet muutokset",
"rcfilters-filter-minor-description": "Muokkaukset, jotka on merkitty pieniksi.",
"rcfilters-filter-watchlistactivity-seen-label": "Nähdyt muutokset",
"rcfilters-filter-watchlistactivity-seen-description": "Muutokset sivuihin, joilla olet käynyt muutosten jälkeen.",
"rcfilters-filtergroup-changetype": "Muutoksen tyyppi",
- "rcfilters-filter-pageedits-label": "Sivun muokkaukset",
+ "rcfilters-filter-pageedits-label": "Sivun muutokset",
"rcfilters-filter-pageedits-description": "Muokkaukset wikin sisältöön, keskusteluihin, luokkakuvauksiin…",
"rcfilters-filter-newpages-label": "Sivujen luonnit",
"rcfilters-filter-newpages-description": "Muokkaukset, joilla on luotu uusia sivuja.",
"recentchangeslinked-feed": "Linkitettyjen sivujen muutokset",
"recentchangeslinked-toolbox": "Linkitettyjen sivujen muutokset",
"recentchangeslinked-title": "Sivulta $1 linkitettyjen sivujen muutokset",
- "recentchangeslinked-summary": "Kirjoita sivun nimi nähdäksesi muutokset sivuihin jotka on linkitetty tai ovat tältä sivulta. (Nähdäksesi luokan jäsenet, kirjoita Luokka:Luokan nimi). Muutokset sivuihin\n[[Special:Watchlist|tarkkailulistallasi]] on <strong>lihavoitu</strong>.",
+ "recentchangeslinked-summary": "Kirjoita sivun nimi nähdäksesi muutokset sivuihin jotka on linkitetty tai ovat tältä sivulta. (Nähdäksesi luokan jäsenet, kirjoita {{ns:category}}:Luokan nimi). Muutokset sivuihin [[Special:Watchlist|tarkkailulistallasi]] on <strong>lihavoitu</strong>.",
"recentchangeslinked-page": "Sivun nimi:",
"recentchangeslinked-to": "Näytä sen sijaan muutokset sivuihin, joista on linkki tähän sivuun",
"recentchanges-page-added-to-category": "[[:$1]] lisätty luokkaan",
"lockmanager-fail-closelock": "Tiedoston $1 lukkotiedostoa ei voitu sulkea.",
"lockmanager-fail-deletelock": "Tiedoston $1 lukkotiedostoa ei voitu poistaa.",
"lockmanager-fail-acquirelock": "Tiedostopolulle \"$1\" ei voitu luoda suojausta.",
- "lockmanager-fail-openlock": "Tiedoston $1 lukkotiedostoa ei voitu avata.",
+ "lockmanager-fail-openlock": "Tiedoston $1 lukkotiedostoa ei voitu avata. Varmista että latauskansiosi on määritetty oikein ja verkkopalvelimellasi on oikeudet kirjoittaa tähän kansioon. Katso https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgUploadDirectory saadaksesi lisätietoja.",
"lockmanager-fail-releaselock": "Tiedoston $1 lukituksen avaaminen epäonnistui.",
"lockmanager-fail-db-bucket": "Ei voitu yhdistää riittävästi tietokantoja kohdassa $1.",
"lockmanager-fail-db-release": "Lukitusten vapauttaminen epäonnistui tietokannassa $1.",
"permissionserrorstext-withaction": "Vous ne pouvez pas $2, pour {{PLURAL:$1|la raison suivante|les raisons suivantes}} :",
"contentmodelediterror": "Vous ne pouvez pas modifier cette révision car son modèle de contenu est <code>$1</code>, ce qui diffère du modèle de contenu actuel de la page <code>$2</code>.",
"recreate-moveddeleted-warn": "<strong>Attention : vous êtes en train de recréer une page qui a été précédemment supprimée.</strong>\n\nAssurez-vous qu'il est pertinent de poursuivre les modifications sur cette page. \nLe journal des suppressions et des déplacements pour cette page est affiché ci-dessous à titre d'information :",
- "moveddeleted-notice": "Cette page a été supprimée. \nLe journal des suppressions, des protections et des déplacements de la page est affiché ci-dessous pour référence.",
- "moveddeleted-notice-recent": "Désolé, cette page a été récemment supprimée (dans les dernières 24 heures).\nLes journaux des suppressions, des protections et des renommages pour la page sont fournis ci-dessous pour référence.",
+ "moveddeleted-notice": "Cette page a été supprimée. \nLes journaux des suppressions, protections et déplacements pour la page sont fournis ci-dessous pour référence.",
+ "moveddeleted-notice-recent": "Désolé, cette page a été récemment supprimée (dans les dernières 24 heures).\nLes journaux des suppressions, protections et déplacements pour la page sont fournis ci-dessous pour référence.",
"log-fulllog": "Voir le journal complet",
"edit-hook-aborted": "Échec de la modification par une extension.\nAucune explication n’a été retournée.",
"edit-gone-missing": "N’a pas pu mettre à jour la page.\nIl semble qu’elle ait été supprimée.",
"revdelete-hide-text": "Texte de la révision",
"revdelete-hide-image": "Masquer le contenu du fichier",
"revdelete-hide-name": "Masquer la cible et les paramètres",
- "revdelete-hide-comment": "Modifier le résumé",
+ "revdelete-hide-comment": "Résumé de modification",
"revdelete-hide-user": "Nom d’utilisateur/Adresse IP de l’éditeur",
"revdelete-hide-restricted": "Supprimer ces données aux administrateurs ainsi qu'aux autres",
"revdelete-radio-same": "(ne pas changer)",
"recentchangeslinked-feed": "Suivi des pages liées",
"recentchangeslinked-toolbox": "Suivi des pages liées",
"recentchangeslinked-title": "Suivi des pages associées à « $1 »",
- "recentchangeslinked-summary": "Entrer un nom de page pour voir les modifications faites récemment sur des pages liées depuis ou vers cette page (pour voir les membres d’une catégorie, entrez Catégorie:Nom de catégorie). Les modifications des pages de [[Special:Watchlist|votre liste de suivi]] sont <strong>en gras</strong>.",
+ "recentchangeslinked-summary": "Entrer un nom de page pour voir les modifications faites récemment sur des pages liées vers ou depuis cette page (pour voir les membres d’une catégorie, entrez {{ns:category}}:Nom de catégorie). Les modifications des pages de [[Special:Watchlist|votre liste de suivi]] sont <strong>en gras</strong>.",
"recentchangeslinked-page": "Nom de la page :",
"recentchangeslinked-to": "Afficher les modifications des pages qui comportent un lien vers la page donnée plutôt que l'inverse",
"recentchanges-page-added-to-category": "[[:$1]] ajouté à la catégorie",
"loginreqlink": "konèkté so kò",
"newarticletext": "Zòt té ka swiv roun lyen vèr roun paj ki pa ka ègzisté òkò. \nAtò di kréyé sa paj, antré zòt tèks annan bwat ki aprè (zòt pé konsilté [$1 paj d'èd-a] pou plis enfòrmasyon).\nSi zòt pa rivé{{GENDER:|}} isi pa éròr, kliké asou bouton <strong>Routour</strong> di zòt navigatò.",
"anontalkpagetext": "----\n<em>Zòt asou paj di diskisyon di oun itilizatò anonim ki pa òkò kréyé di kont ou ki pa ka an itilizé</em>.\nPou sa rézon, nou divèt itilizé so adrès IP pou idantifyé li.\nOun adrès IP pé sa partajé pa plizyò itilizatò.\nSi zòt roun itiliza{{GENDER:|ò|ris}} anonim é si zòt ka kontasté ki dé koumantèr ki pa ka konsèrné zòt sa adrèsé à zòt, zòt pé [[Special:CreateAccount|kréyé roun kont]] ou [[Special:UserLogin|konèkté zòt kò]] atò di évité tout konfizyon fitir ké ròt kontribitò anonim.",
- "noarticletext": "I pa gen pou moman-an pyès tèks asou sa paj.\nZòt pé [[Special:Search/{{PAGENAME}}|lansé oun sasé asou sa tit]] annan ròt paj-ya,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sasé annan opérasyon-yan lyé]\nou [{{fullurl:{{FULLPAGENAME}}|action=edit}} kréyé sa paj]</span>.",
- "noarticletext-nopermission": "I pa gen pou moman-an pyès tèks asou sa paj.\nZòt pé [[Special:Search/{{PAGENAME}}|fè roun sasé asou sa tit]] andan ròt paj-ya,\nou <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|paj={{FULLPAGENAMEE}}}} sasé andan journal asosyé]</span>, mè zòt pa gen pèrmisyon di kréyé sa paj.",
+ "noarticletext": "I pa gen atchwèlman pyès tèks asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|lansé oun sasé asou sa tit]] annan ròt paj-ya,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} sasé annan opérasyon lyé]\noben [{{fullurl:{{FULLPAGENAME}}|action=edit}} kréyé sa paj]</span>.",
+ "noarticletext-nopermission": "I pa gen atchwèlman pyès tèks asou sa paj.\nZòt pouvé [[Special:Search/{{PAGENAME}}|fè roun sasé asou sa tit]] andan ròt paj-ya,\noben <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|paj={{FULLPAGENAMEE}}}} sasé annan journal asosyé]</span>, mè zòt pa gen pèrmisyon di kréyé sa paj.",
"userpage-userdoesnotexist-view": "Kont itilizatò-a « $1 » pa anréjistré.",
"clearyourcache": "<strong>Nòt :</strong> aprè zòt anréjistré zòt modifikasyon, zòt divèt forsé roucharjman konplè di kach di zòt navigatò pou wè chanjman-yan.\n* <strong>Firefox / Safari :</strong> mentné touch-a <em>Maj</em> (<em>Shift</em>) an klikan asou bouton-an <em>Atchwalizé</em> ou présé <em>Ctrl-F5</em> ou <em>Ctrl-R</em> (<em>⌘-R</em> asou roun Mac) \n* <strong>Google Chrome :</strong> apwiyé asou <em>Ctrl-Maj-R</em> (<em>⌘-Shift-R</em> asou roun Mac) \n* <strong>Internet Explorer :</strong> mentné touch-a <em>Ctrl</em> an klikan asou bouton-an <em>Atchwalizé</em> ou présé <em>Ctrl-F5</em> \n* <strong>Opera :</strong> alé annan <em>Menu → Settings</em> (<em>Opera → Préférences</em> asou roun Mac) é answit à <em>Konfidansyalité & sékrité → Éfasé doné d'èksplorasyon-yan → Imaj ké fiché an kach</em>.",
"previewnote": "<strong>Raplé-zòt ki a jis roun prévizwalizasyon.</strong>\nZòt modifikasyon pa òkò anréjistré !",
"sp-contributions-newonly": "Afiché inikman modifikasyon-yan ki sa dé kréyasyon di paj",
"sp-contributions-submit": "Sasé",
"whatlinkshere": "Paj lyé",
- "whatlinkshere-title": "Paj ki ka pwenté vèr « $1 »",
+ "whatlinkshere-title": "Paj ki ka pwenté bò'd « $1 »",
"whatlinkshere-page": "Paj :",
"linkshere": "Paj-ya ki anba ka kontni roun lyen vèr <strong>[[:$1]]</strong> :",
"nolinkshere": "Pyès paj pa gen kontni dé lyen vèr <strong>[[:$1]]</strong>.",
"customcssprotected": "Non ten os permisos necesarios para modificar esta páxina de CSS, dado que contén a configuración persoal doutro usuario.",
"customjsprotected": "Non ten os permisos necesarios para modificar esta páxina de JavaScript, dado que contén a configuración persoal doutro usuario.",
"mycustomcssprotected": "Non ten os permisos necesarios para editar esta páxina de CSS.",
+ "mycustomjsonprotected": "Non ten permisos para editar esta páxina JSON.",
"mycustomjsprotected": "Non ten os permisos necesarios para editar esta páxina de JavaScript.",
"myprivateinfoprotected": "Non ten os permisos necesarios para editar a súa información privada.",
"mypreferencesprotected": "Non ten os permisos necesarios para editar as súas preferencias.",
"wrongpasswordempty": "O campo do contrasinal estaba en branco.\nPor favor, inténteo de novo.",
"passwordtooshort": "Os contrasinais deben conter, como mínimo, {{PLURAL:$1|1 carácter|$1 caracteres}}.",
"passwordtoolong": "Os contrasinais non poden ser máis longo de {{PLURAL:$1|1 carácter|$1 caracteres}}.",
- "passwordtoopopular": "Non pode utilizar un contrasinal dos habitualmente elixidos pola xente. Por favor, escolla un contrasinal máis orixinal.",
+ "passwordtoopopular": "Non pode utilizar un contrasinal dos habitualmente elixidos pola xente. Por favor, escolla un contrasinal que sexa máis complicada de adiviñar.",
"password-name-match": "O seu contrasinal debe ser diferente do seu nome de usuario.",
"password-login-forbidden": "O uso deste nome de usuario e contrasinal foi prohibido.",
"mailmypassword": "Restablecer o contrasinal",
"passwordremindertitle": "Novo contrasinal temporal para {{SITENAME}}",
- "passwordremindertext": "Alguén (probablemente vostede, desde o enderezo IP $1) solicitou un novo\ncontrasinal para acceder a {{SITENAME}} ($4). Creouse un contrasinal temporal para o usuario\n\"$2\" e quedou establecido como \"$3\". Se esa foi a súa\nintención, terá que acceder ao sistema e escoller un novo contrasinal agora.\nO seu contrasinal temporal caducará {{PLURAL:$5|nun día|en $5 días}}.\n\nSe foi outra persoa a que fixo esta solicitude ou se xa se lembra do seu contrasinal\ne non o quere modificar, pode ignorar esta mensaxe e\ncontinuar a utilizar o seu contrasinal vello.",
+ "passwordremindertext": "Alguén (desde o enderezo IP $1) solicitou un novo\ncontrasinal para acceder a {{SITENAME}} ($4). Creouse un contrasinal temporal para o usuario\n\"$2\" e quedou establecido como \"$3\". Se esa foi a súa\nintención, terá que acceder ao sistema e escoller un novo contrasinal agora.\nO seu contrasinal temporal caducará {{PLURAL:$5|nun día|en $5 días}}.\n\nSe foi outra persoa a que fixo esta solicitude ou se xa se lembra do seu contrasinal\ne non o quere modificar, pode ignorar esta mensaxe e\ncontinuar a utilizar o seu contrasinal vello.",
"noemail": "O usuario \"$1\" non posúe ningún enderezo de correo electrónico rexistrado.",
"noemailcreate": "Ten que proporcionar un enderezo de correo electrónico válido",
"passwordsent": "Enviouse un contrasinal novo ao enderezo de correo electrónico rexistrado de \"$1\".\nPor favor, acceda ao sistema de novo tras recibilo.",
"sitecsspreview": "'''Lembre que só está vendo a vista previa deste CSS.'''\n'''Este aínda non foi gardado!'''",
"sitejsonpreview": "<strong>Lembre que tan só está previsualizando esta configuración JSON.\nAínda non foi gardada!</strong>",
"sitejspreview": "'''Lembre que só está vendo a vista previa deste código JavaScript.'''\n'''Este aínda non foi gardado!'''",
- "userinvalidconfigtitle": "<strong>Aviso:</strong> Non hai ningunha aparencia chamada \"$1\".\nLembre que as páxinas .css e .js personalizadas utilizan un título en minúsculas, como por exemplo \"{{ns:user}}:Exemplo/vector.css\" no canto de \"{{ns:user}}:Exemplo/Vector.css\".",
+ "userinvalidconfigtitle": "<strong>Aviso:</strong> Non hai ningunha aparencia chamada \"$1\".\nLembre que as páxinas .css, .json e .js personalizadas utilizan un título en minúsculas, como por exemplo \"{{ns:user}}:Exemplo/vector.css\" no canto de \"{{ns:user}}:Exemplo/Vector.css\".",
"updated": "(Actualizado)",
"note": "'''Nota:'''",
"previewnote": "<strong>Lembre que esta é só unha vista previa.</strong>\nAínda non gardou os seus cambios!",
"longpageerror": "'''Erro: O texto que pretende gardar ocupa {{PLURAL:$1|$1 kilobyte|$1 kilobytes}}, e existe un límite dun máximo de {{PLURAL:$2|$2 kilobyte|$2 kilobytes}}.'''\nPolo tanto, non se pode gardar.",
"readonlywarning": "<strong>Atención: Pechouse a base de datos para facer mantemento, polo que non vai poder gardar as súas edicións polo de agora.</strong>\nSe cadra, pode cortar e pegar o texto nun ficheiro de texto e gardalo para despois.\n\nO administrador do sistema que a pechou deu esta explicación: $1",
"protectedpagewarning": "'''Aviso: Esta páxina foi protexida de xeito que só os usuarios con privilexios de administrador a poidan editar.'''\nVelaquí está a última entrada no rexistro, por se quere consultala:",
- "semiprotectedpagewarning": "'''Nota:''' Esta páxina foi protexida de xeito que só os usuarios rexistrados a poidan editar.\nVelaquí está a última entrada no rexistro, por se quere consultala:",
+ "semiprotectedpagewarning": "<strong>Nota:</strong> Esta páxina foi protexida de xeito que só os usuarios autoconfirmados a poidan editar.\nVelaquí está a última entrada no rexistro, por se quere consultala:",
"cascadeprotectedwarning": "<strong>Atención:</strong> Protexeuse esta páxina de xeito que só a poden editar os usuarios con [[Special:ListGroupRights|privilexios específicos]] debido a que está transcluída {{PLURAL:$1|na seguinte páxina protexida|nas seguintes páxinas protexidas}} coa opción \"protección en serie\" activada:",
"titleprotectedwarning": "'''Aviso: Esta páxina foi protexida de xeito que [[Special:ListGroupRights|só algúns usuarios]] a poidan crear.'''\nVelaquí está a última entrada no rexistro, por se quere consultala:",
"templatesused": "{{PLURAL:$1|Modelo usado|Modelos usados}} nesta páxina:",
"prefs-dateformat": "Formato da data",
"prefs-timeoffset": "Desprazamento horario",
"prefs-advancedediting": "Opcións xerais",
+ "prefs-developertools": "Ferramentas de desenvolvemento",
"prefs-editor": "Editor",
"prefs-preview": "Vista previa",
"prefs-advancedrc": "Opcións avanzadas",
"rcfilters-filter-humans-description": "Edicións realizadas por editores humanos.",
"rcfilters-filtergroup-reviewstatus": "Estado de revisión",
"rcfilters-filter-reviewstatus-unpatrolled-label": "Sen patrullar",
+ "rcfilters-filter-reviewstatus-manual-description": "Edicións marcadas manualmente como vixiadas.",
+ "rcfilters-filter-reviewstatus-manual-label": "Vixiadas manualmente",
+ "rcfilters-filter-reviewstatus-auto-description": "Edicións realizadas por usuarios avanzados cuxo traballo márcase automaticamente como vixiado.",
+ "rcfilters-filter-reviewstatus-auto-label": "Vixiado automaticamente",
"rcfilters-filtergroup-significance": "Importancia",
"rcfilters-filter-minor-label": "Edicións menores",
"rcfilters-filter-minor-description": "Edicións que o autor etiquetou como menores.",
"rollback-success": "Desfixéronse as edicións de {{GENDER:$3|$1}};\nvolveuse á última edición, feita por {{GENDER:$4|$2}}.",
"rollback-success-notify": "Revertéronse as edicións de $1;\nrestaurouse a última revisión de $2. [$3 Mostrar os cambios]",
"sessionfailure-title": "Erro de sesión",
- "sessionfailure": "Parece que hai un problema co rexistro da súa sesión;\nesta acción cancelouse como precaución fronte ao secuestro de sesións.\nPrema no botón \"atrás\", volva cargar a páxina da que proviña e inténteo de novo.",
+ "sessionfailure": "Parece que hai un problema co rexistro da súa sesión;\nesta acción cancelouse como precaución fronte ao secuestro de sesións.\nPor favor, volva enviar o formulario.",
"changecontentmodel": "Cambiar o modelo de contido dunha páxina",
"changecontentmodel-legend": "Cambiar o modelo de contido",
"changecontentmodel-title-label": "Título da páxina",
"fix-double-redirects": "Actualizar calquera redirección que apunte cara ao título orixinal",
"move-leave-redirect": "Deixar unha redirección detrás",
"protectedpagemovewarning": "'''Aviso:''' Esta páxina foi protexida de xeito que só os usuarios con privilexios de administrador a poidan mover.\nVelaquí está a última entrada no rexistro, por se quere consultala:",
- "semiprotectedpagemovewarning": "'''Nota:''' Esta páxina foi protexida de xeito que só os usuarios rexistrados a poidan mover.\nVelaquí está a última entrada no rexistro, por se quere consultala:",
+ "semiprotectedpagemovewarning": "<strong>Nota:</strong> Esta páxina foi protexida de xeito que só os usuarios autoconfirmados a poidan mover.\nVelaquí está a última entrada no rexistro, por se quere consultala:",
"move-over-sharedrepo": "\"[[:$1]]\" xa existe nun repositorio compartido. Ao mover un ficheiro a este título sobrescribirase o ficheiro compartido.",
"file-exists-sharedrepo": "O nome que elixiu para o ficheiro xa está en uso nun repositorio compartido.\nPor favor, escolla outro nome.",
"export": "Exportar páxinas",
"unlinkaccounts-success": "A conta foi desvinculada.",
"authenticationdatachange-ignored": "Os cambios de datos de autenticación non foron xerados. Está configurado o provedor?",
"userjsispublic": "Lembre: As subpáxinas JavaScript non deberían conter datos confidenciais porque outros usuarios poden velos.",
+ "userjsonispublic": "Por favor, teña en conta queː as subpáxinas JSON non deben conter datos confidenciais xa que son visibles por outros usuarios.",
"usercssispublic": "Lembre: As subpáxinas CSS non deberían conter datos confidenciais porque outros usuarios poden velos.",
"restrictionsfield-badip": "Enderezo IP ou rango de IP non válido: $1",
"restrictionsfield-label": "Rangos de IP permitidos:",
"Ammarpad"
]
},
- "tog-underline": "A shaya zaruruwa",
+ "tog-underline": "Link underlining:",
"tog-hideminor": "A ɓoye ƙananan gyare-gyare na baya-bayan nan",
"tog-hidepatrolled": "A ɓoye gyare-gyaren kan ido a cikin gyare-gyare bayan-bayan nan",
"tog-newpageshidepatrolled": "A ɓoye shafuna kan ido a cikin sabbin shafuna",
"missingarticle-rev": "(lambar zubi: $1)",
"badtitletext": "Kan shafin da aka nema bai da ma'ana, ko kango ne, ko kuma wani kai ne na tsakanin harsuna ko shire-shire da bai da mahaɗi mai kyau.\nTana yiyuwa yana da harafi ko haruffa da ba su karɓuwa cikin kanu.",
"viewsource": "Duba tushe",
+ "ns-specialprotected": "Shafuka na musamman ba za a iya gyra su ba.",
+ "logouttext": "Yanzu kun yi login out.",
+ "cannotlogoutnow-title": "Ba za ku iya login out ba yanzu. Ku sake gwadawa.",
+ "welcomeuser": "Barka da zuwa, $1!",
+ "welcomecreation-msg": "Yanzu kayi kirkiri sabon account.",
"yourname": "Sunan ma'aikaci:",
"userlogin-yourname": "Suna mai amfani",
"userlogin-yourname-ph": "Shiga sunanka mai amfani",
"logout": "Fita",
"userlogout": "Fita",
"createaccount": "ƙirƙira asusu",
+ "userlogin-resetpassword-link": "Ka manta lambobin sirrinka?",
"createacct-emailrequired": "adireshin i-mel",
"createacct-emailoptional": "adireshin i-mel (zaɓi)",
"createacct-email-ph": "shiga adireshinka i-mel",
"rcfilters-savedqueries-remove": "הסרה",
"rcfilters-savedqueries-new-name-label": "שם",
"rcfilters-savedqueries-new-name-placeholder": "תיאור מטרת המסנן",
- "rcfilters-savedqueries-apply-label": "יצירת מסנן",
+ "rcfilters-savedqueries-apply-label": "×\99צ×\99רת ×\94×\9e×¡× ×\9f",
"rcfilters-savedqueries-apply-and-setdefault-label": "יצירת מסנן התחלתי",
"rcfilters-savedqueries-cancel-label": "ביטול",
"rcfilters-savedqueries-add-new-title": "שמירת הגדרות המסננים הנוכחיות",
"recentchangeslinked-feed": "שינויים בדפים המקושרים",
"recentchangeslinked-toolbox": "שינויים בדפים המקושרים",
"recentchangeslinked-title": "שינויים בדפים המקושרים מהדף \"$1\"",
- "recentchangeslinked-summary": "יש להקליד שם דף כדי לראות את השינויים בדפים המקשרים לדף זה או המקושרים ממנו. (כדי לראות את הדפים החברים בקטגוריה, יש להקליד \"קטגוריה:שם הקטגוריה\".) שינויים בדפים ב[[Special:Watchlist|רשימת המעקב שלך]] מוצגים ב<strong>הדגשה</strong>.",
+ "recentchangeslinked-summary": "יש להקליד שם דף כדי לראות את השינויים בדפים המקשרים לדף זה או המקושרים ממנו. (כדי לראות את הדפים החברים בקטגוריה, יש להקליד \"{{ns:category}}:שם הקטגוריה\".) שינויים בדפים ב[[Special:Watchlist|רשימת המעקב שלך]] מוצגים ב<strong>הדגשה</strong>.",
"recentchangeslinked-page": "שם הדף:",
"recentchangeslinked-to": "הצגת השינויים בדפים המקשרים לדף הנתון במקום זאת",
"recentchanges-page-added-to-category": "הדף [[:$1]] נוסף לקטגוריה",
"recentchanges-page-added-to-category-bundled": "הדף [[:$1]] נוסף לקטגוריה, [[Special:WhatLinksHere/$1|והוא מוכלל בדפים אחרים]]",
"recentchanges-page-removed-from-category": "הדף [[:$1]] הוסר מהקטגוריה",
- "recentchanges-page-removed-from-category-bundled": "הדף [[:$1]] הוסר מהקטגוריה, ו[[Special:WhatLinksHere/$1|הוא מוכלל בדפים אחרים]]",
+ "recentchanges-page-removed-from-category-bundled": "הדף [[:$1]] הוסר מהקטגוריה, [[Special:WhatLinksHere/$1|והוא מוכלל בדפים אחרים]]",
"autochange-username": "שינוי אוטומטי של מדיה־ויקי",
"upload": "העלאת קובץ",
"uploadbtn": "העלאת הקובץ",
- "reuploaddesc": "×\91×\99×\98×\95×\9c ×\94×\94×¢×\9c×\90×\94 ×\95×\97×\96ר×\94 ×\9c×\98×\95פס ×\94×¢×\9c×\90ת ק×\91צ×\99×\9d ×\9cשרת",
+ "reuploaddesc": "×\91×\99×\98×\95×\9c ×\94×\94×¢×\9c×\90×\94 ×\95×\97×\96ר×\94 ×\9c×\98×\95פס ×\94×¢×\9c×\90ת ×\94ק×\91צ×\99×\9d",
"upload-tryagain": "שליחת התיאור החדש של הקובץ",
"upload-tryagain-nostash": "שליחת הקובץ המועלה מחדש והתיאור המעודכן",
"uploadnologin": "לא נכנסת לחשבון",
"uploadnologintext": "נדרשת $1 כדי להעלות קבצים.",
"upload_directory_missing": "שרת האינטרנט אינו יכול ליצור את תיקיית ההעלאות ($1) החסרה.",
"upload_directory_read_only": "שרת האינטרנט אינו יכול לכתוב בתיקיית ההעלאות ($1).",
- "uploaderror": "ש×\92×\99×\90×\94 ×\91×\94×¢×\9c×\90ת ×\94ק×\95×\91×¥",
- "upload-recreate-warning": "'''אזהרה: קובץ בשם זה נמחק או הועבר.'''\n\nיומני המחיקות וההעברות של הדף מוצגים להלן:",
- "uploadtext": "×\94שת×\9eש×\95 ×\91×\98×\95פס ×\9c×\94×\9c×\9f ×\9b×\93×\99 ×\9c×\94×¢×\9c×\95ת ק×\91צ×\99×\9d.\n×\9b×\93×\99 ×\9cר×\90×\95ת ×\90×\95 ×\9c×\97פש ק×\91צ×\99×\9d ש×\94×\95×¢×\9c×\95 ×\91×¢×\91ר ×\90× ×\90 ×¤× ×\95 ×\9c[[Special:FileList|רש×\99×\9eת ×\94ק×\91צ×\99×\9d ש×\94×\95×¢×\9c×\95]], ×\95×\9b×\9e×\95 ×\9b×\9f, ×\94×¢×\9c×\90×\95ת (×\9b×\95×\9c×\9c ×\94×¢×\9c×\90×\95ת ש×\9c ×\92רס×\94 ×\97×\93ש×\94) ×\9e×\95צ×\92×\95ת ×\91[[Special:Log/upload|×\99×\95×\9e×\9f ×\94×\94×¢×\9c×\90×\95ת]], ×\95×\9e×\97×\99ק×\95ת ×\91[[Special:Log/delete|×\99×\95×\9e×\9f ×\94×\9e×\97×\99ק×\95ת]].\n\n×\9b×\93×\99 ×\9c×\9b×\9c×\95×\9c ק×\95×\91×¥ ×\91×\93×£, ×\94שת×\9eש×\95 ×\91ק×\99ש×\95ר ×\91×\90×\97ת ×\94צ×\95ר×\95ת ×\94×\91×\90×\95ת:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code>''' ×\9cש×\99×\9e×\95ש ×\91×\92רס×\94 ×\94×\9e×\9c×\90×\94 ש×\9c ×\94ק×\95×\91×¥\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|×\98קס×\98 ת×\99×\90×\95ר]]</nowiki></code>''' ×\9cש×\99×\9e×\95ש ×\91×\92רס×\94 ×\9e×\95ק×\98× ×ª ×\91ר×\95×\97×\91 200 פ×\99קס×\9c×\99×\9d ×\91ת×\99×\91×\94 ×\91צ×\93 ש×\9e×\90×\9c ש×\9c ×\94×\93×£, ×¢×\9d '×\98קס×\98 ת×\99×\90×\95ר' ×\9bת×\99×\90×\95ר\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code>''' לקישור ישיר לקובץ בלי להציגו",
+ "uploaderror": "ש×\92×\99×\90×\94 ×\91×\94×¢×\9c×\90×\94",
+ "upload-recreate-warning": "<strong>אזהרה: קובץ בשם זה נמחק או הועבר.</strong>\n\nיומני המחיקות וההעברות של הדף מוצגים להלן:",
+ "uploadtext": "× ×\99ת×\9f ×\9c×\94שת×\9eש ×\91×\98×\95פס ש×\9c×\94×\9c×\9f ×\9b×\93×\99 ×\9c×\94×¢×\9c×\95ת ק×\91צ×\99×\9d.\n×\91×\90פשר×\95ת×\9a ×\9cר×\90×\95ת ×\90×\95 ×\9c×\97פש ק×\91צ×\99×\9d ש×\94×\95×¢×\9c×\95 ×\91×¢×\91ר ×\91[[Special:FileList|רש×\99×\9eת ×\94ק×\91צ×\99×\9d ש×\94×\95×¢×\9c×\95]]. ×\9b×\9e×\95Ö¾×\9b×\9f, ×\94×¢×\9c×\90×\95ת (×\9b×\95×\9c×\9c ×\94×¢×\9c×\90×\95ת ש×\9c ×\92רס×\94 ×\97×\93ש×\94) ×\9e×\95צ×\92×\95ת ×\91[[Special:Log/upload|×\99×\95×\9e×\9f ×\94×\94×¢×\9c×\90×\95ת]], ×\95×\9e×\97×\99ק×\95ת ×\9e×\95צ×\92×\95ת ×\91[[Special:Log/delete|×\99×\95×\9e×\9f ×\94×\9e×\97×\99ק×\95ת]].\n\n×\9b×\93×\99 ×\9c×\9b×\9c×\95×\9c ק×\95×\91×¥ ×\91×\93×£, ×\99ש ×\9c×\94שת×\9eש ×\91ק×\99ש×\95ר ×\91×\90×\97ת ×\94צ×\95ר×\95ת ×\94×\91×\90×\95ת:\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code></strong> ×\9cש×\99×\9e×\95ש ×\91×\92רס×\94 ×\94×\9e×\9c×\90×\94 ש×\9c ×\94ק×\95×\91×¥\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|×\98קס×\98 ת×\99×\90×\95ר]]</nowiki></code></strong> ×\9cש×\99×\9e×\95ש ×\91×\92רס×\94 ×\9e×\95ק×\98× ×ª ×\91ר×\95×\97×\91 200 פ×\99קס×\9c×\99×\9d ×\91ת×\99×\91×\94 ×\91צ×\93 ש×\9e×\90×\9c ש×\9c ×\94×\93×£ ×¢×\9d ×\98קס×\98 ×\9cת×\99×\90×\95ר\n* <strong><code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code></strong> לקישור ישיר לקובץ בלי להציגו",
"upload-permitted": "{{PLURAL:$2|סוג קובץ מותר|סוגי קבצים מותרים}}: $1.",
"upload-preferred": "{{PLURAL:$2|סוג קובץ מומלץ|סוגי קבצים מומלצים}}: $1.",
"upload-prohibited": "{{PLURAL:$2|סוג קובץ אסור|סוגי קבצים אסורים}}: $1.",
"uploadlogpage": "יומן העלאות",
- "uploadlogpagetext": "×\9c×\94×\9c×\9f רש×\99×\9e×\94 ש×\9c ×\94×¢×\9c×\90×\95ת ×\94ק×\91צ×\99×\9d ×\94×\90×\97ר×\95× ×\95ת ש×\91×\95צע×\95.\nר×\90×\95 ×\90ת [[Special:NewFiles|גלריית הקבצים החדשים]] להצגה ויזואלית שלהם.",
+ "uploadlogpagetext": "×\9c×\94×\9c×\9f רש×\99×\9e×\94 ש×\9c ×\94×¢×\9c×\90×\95ת ×\94ק×\91צ×\99×\9d ×\94×\90×\97ר×\95× ×\95ת ש×\91×\95צע×\95.\n×\90פשר ×\9c×¢×\99×\99×\9f ×\91[[Special:NewFiles|גלריית הקבצים החדשים]] להצגה ויזואלית שלהם.",
"filename": "שם הקובץ",
"filedesc": "תקציר",
"fileuploadsummary": "תיאור:",
"ignorewarning": "התעלמות מהאזהרה ושמירת הקובץ בכל זאת",
"ignorewarnings": "התעלמות מכל האזהרות",
"minlength1": "שמות קבצים צריכים להיות בני תו אחד לפחות.",
- "illegalfilename": "ש×\9d ×\94ק×\95×\91×¥ \"$1\" ×\9e×\9b×\99×\9c ת×\95×\95×\99×\9d ש×\90×\99× ×\9d ×\9e×\95תר×\99×\9d ×\91×\9b×\95תר×\95ת ×\93פ×\99×\9d.\n× ×\90 ×\9c×©× ×\95ת ×\90ת ×\94ש×\9d ולנסות להעלותו שנית.",
+ "illegalfilename": "ש×\9d ×\94ק×\95×\91×¥ \"$1\" ×\9e×\9b×\99×\9c ת×\95×\95×\99×\9d ש×\90×\99× ×\9d ×\9e×\95תר×\99×\9d ×\91×\9b×\95תר×\95ת ×\93פ×\99×\9d.\n× ×\90 ×\9c×©× ×\95ת ×\90ת ש×\9d ×\94ק×\95×\91×¥ ולנסות להעלותו שנית.",
"filename-toolong": "שמות של קבצים לא יכולים להיות ארוכים יותר מ־240 בתים.",
"badfilename": "שם הקובץ שונה ל־\"$1\".",
- "filetype-mime-mismatch": "סיומת הקובץ \".$1\" אינה מתאימה לסוג ה־MIME שנמצא לקובץ זה ($2).",
+ "filetype-mime-mismatch": "סיומת הקובץ \"<span dir=\"ltr\">.$1</span>\" אינה מתאימה לסוג ה־MIME שנמצא לקובץ זה ($2).",
"filetype-badmime": "לא ניתן להעלות קבצים שסוג ה־MIME שלהם הוא \"$1\".",
"filetype-bad-ie-mime": "לא ניתן להעלות קובץ זה, כיוון שאינטרנט אקספלורר יזהה אותו כקובץ מסוג \"$1\", שהוא סוג קובץ אסור שעלול להיות מסוכן.",
- "filetype-unwanted-type": "'''\".$1\"''' הוא סוג קובץ בלתי מומלץ.\n{{PLURAL:$3|סוג הקובץ המומלץ הוא|סוגי הקבצים המומלצים הם}} $2.",
- "filetype-banned-type": "'''\".$1\"''' {{PLURAL:$4|הוא סוג קובץ אסור להעלאה|הם סוגי קבצים אסורים להעלאה}}.\n{{PLURAL:$3|סוג הקובץ המותר הוא|סוגי הקבצים המותרים הם}} $2.",
+ "filetype-unwanted-type": "<strong dir=\"ltr\">\".$1\"</strong> הוא סוג קובץ בלתי־מומלץ.\n{{PLURAL:$3|סוג הקובץ המומלץ הוא|סוגי הקבצים המומלצים הם}} $2.",
+ "filetype-banned-type": "<strong dir=\"ltr\">\".$1\"</strong> {{PLURAL:$4|הוא סוג קובץ אסור להעלאה|הם סוגי קבצים אסורים להעלאה}}.\n{{PLURAL:$3|סוג הקובץ המותר הוא|סוגי הקבצים המותרים הם}} $2.",
"filetype-missing": "לקובץ אין סיומת (כדוגמת \"<span dir=\"ltr\">.jpg</span>\").",
- "empty-file": "הקובץ ששלחת היה ריק",
- "file-too-large": "הקובץ ששלחת היה גדול מדי",
- "filename-tooshort": "שם הקובץ קצר מדי",
+ "empty-file": "הקובץ ששלחת היה ריק.",
+ "file-too-large": "הקובץ ששלחת היה גדול מדי.",
+ "filename-tooshort": "שם הקובץ קצר מדי.",
"filetype-banned": "אסור להעלות קבצים מהסוג הזה.",
- "verification-error": "קובץ זה לא עבר את תהליך אימות הקבצים",
+ "verification-error": "קובץ זה לא עבר את תהליך אימות הקבצים.",
"hookaborted": "השינוי שניסית לבצע הופסק על־ידי הרחבה.",
- "illegal-filename": "שם הקובץ אינו מותר להעלאה",
- "overwrite": "דריסת קובץ קיים אינה מותרת",
- "unknown-error": "אירעה שגיאה בלתי ידועה",
- "tmp-create-error": "לא ניתן ליצור קובץ זמני",
- "tmp-write-error": "שגיאה בכתיבה לקובץ הזמני",
- "large-file": "מומלץ שהקבצים לא יהיו גדולים יותר מ־$1 (גודל הקובץ שהעליתם הוא $2).",
+ "illegal-filename": "שם הקובץ אינו מותר להעלאה.",
+ "overwrite": "דריסת קובץ קיים אינה מותרת.",
+ "unknown-error": "אירעה שגיאה בלתי־ידועה.",
+ "tmp-create-error": "לא ניתן ליצור קובץ זמני.",
+ "tmp-write-error": "שגיאה בכתיבה לקובץ הזמני.",
+ "large-file": "מומלץ שהקבצים לא יהיו גדולים יותר מ{{GRAMMAR:תחילית|$1}}\n(גודל הקובץ שהעלית הוא $2).",
"largefileserver": "גודל הקובץ חורג ממגבלת השרת.",
"emptyfile": "נראה שהקובץ שהעלית ריק.\nייתכן שהסיבה לכך היא שגיאת הקלדה בשם הקובץ.\nיש לוודא שזה הקובץ שברצונך להעלות.",
"windows-nonascii-filename": "אתר ויקי זה אינו תומך בשמות קבצים עם תווים מיוחדים או תווים שאינם באנגלית.",
- "fileexists": "קובץ בשם הזה כבר קיים, אנא בִּדקו את <strong>[[:$1]]</strong> אם אינכם בטוחים שברצונכם להחליף אותו.\n[[$1|thumb]]",
- "filepageexists": "×\93×£ ת×\99×\90×\95ר ×\94ק×\95×\91×¥ ×¢×\91×\95ר ק×\95×\91×¥ ×\96×\94 ×\9b×\91ר × ×\95צר ×\91<strong>[[:$1]]</strong>, ×\90×\9a ×\9c×\90 ק×\99×\99×\9d ק×\95×\91×¥ ×\91ש×\9d ×\96×\94.\nת×\99×\90×\95ר ×\94ק×\95×\91×¥ שת×\9bת×\91×\95 ×\9c×\90 ×\99×\95פ×\99×¢ ×\91×\93×£ ת×\99×\90×\95ר ×\94ק×\95×\91×¥.\n×\9b×\93×\99 ×\9c×\92ר×\95×\9d ×\9c×\95 ×\9c×\94×\95פ×\99×¢ ש×\9d, ×\99×\94×\99×\94 ×¢×\9c×\99×\9b×\9d ×\9cער×\95×\9a ×\90×\95ת×\95 ×\99×\93× ×\99ת. [[$1|thumb]]",
+ "fileexists": "קובץ בשם הזה כבר קיים, אנא {{GENDER:|בדוק|בדקי|בדקו}} את <strong>[[:$1]]</strong> אם {{GENDER:|אינך בטוח שברצונך|אינך בטוחה שברצונך|אינכם בטוחים שברצונכם}} להחליף אותו.\n[[$1|thumb]]",
+ "filepageexists": "×\93×£ ×\94ת×\99×\90×\95ר ×¢×\91×\95ר ק×\95×\91×¥ ×\96×\94 ×\9b×\91ר × ×\95צר ×\91×\93×£ <strong>[[:$1]]</strong>, ×\90×\9a ×\9c×\90 ק×\99×\99×\9d ק×\95×\91×¥ ×\91ש×\9d ×\96×\94.\nת×\99×\90×\95ר ×\94ק×\95×\91×¥ ש×\99×\99×\9bת×\91 ×\9b×\90×\9f ×\9c×\90 ×\99×\95פ×\99×¢ ×\91×\93×£ ת×\99×\90×\95ר ×\94ק×\95×\91×¥.\n×\9b×\93×\99 ×\9c×\92ר×\95×\9d ×\9c×\95 ×\9c×\94×\95פ×\99×¢ ש×\9d, ×\99×\94×\99×\94 צ×\95ר×\9a ×\9cער×\95×\9a ×\90×\95ת×\95 ×\99×\93× ×\99ת.\n[[$1|thumb]]",
"fileexists-extension": "קובץ עם שם דומה כבר קיים: [[$2|thumb]]\n* שם הקובץ המועלה: <strong>[[:$1]]</strong>\n* שם הקובץ הקיים: <strong>[[:$2]]</strong>\nאולי כדאי לתת לקובץ שם ספציפי יותר?",
"fileexists-thumbnail-yes": "נראה שהקובץ הוא תמונה מוקטנת (ממוזערת).\n[[$1|thumb]]\nיש לבדוק את הקובץ <strong>[[:$1]]</strong>.\nאם הקובץ שבדקת הוא אותה התמונה בגודל מקורי, אין זה הכרחי להעלות גם תמונה ממוזערת.",
"file-thumbnail-no": "שם הקובץ מתחיל ב־<strong>$1</strong>.\nנראה שזוהי תמונה מוקטנת (ממוזערת).\nאם התמונה בגודל מלא מצויה ברשותך, יש להעלות אותה ולא את התמונה הממוזערת; אחרת, יש לשנות את שם הקובץ.",
- "fileexists-forbidden": "ק×\95×\91×¥ ×\91ש×\9d ×\96×\94 ×\9b×\91ר ק×\99×\99×\9d, ×\95×\90×\99× ×\9b×\9d ×\99×\9b×\95×\9c×\99×\9d ×\9c×\94×\97×\9c×\99×£ ×\90×\95ת×\95.\n×\90×\9d ×\90ת×\9d ×¢×\93×\99×\99×\9f ×\9e×¢×\95× ×\99×\99× ×\99×\9d ×\9c×\94×¢×\9c×\95ת ק×\95×\91×¥ ×\96×\94, ×\90× ×\90 ×\97×\96ר×\95 ×\9c×\93×£ ×\94ק×\95×\93×\9d ×\95×\94×¢×\9c×\95 את הקובץ תחת שם חדש.\n[[File:$1|thumb|center|$1]]",
- "fileexists-shared-forbidden": "ק×\95×\91×¥ ×\91ש×\9d ×\96×\94 ×\9b×\91ר ק×\99×\99×\9d ×\9bק×\95×\91×¥ ×\9eש×\95תף.\n×\90×\9d ×\90ת×\9d ×¢×\93×\99×\99×\9f ×\9e×¢×\95× ×\99×\99× ×\99×\9d ×\9c×\94×¢×\9c×\95ת ק×\95×\91×¥ ×\96×\94, ×\90× ×\90 ×\97×\96ר×\95 ×\9c×\93×£ ×\94ק×\95×\93×\9d ×\95×\94×¢×\9c×\95 את הקובץ תחת שם חדש.\n[[File:$1|thumb|center|$1]]",
+ "fileexists-forbidden": "ק×\95×\91×¥ ×\91ש×\9d ×\96×\94 ×\9b×\91ר ק×\99×\99×\9d, ×\95×\9c×\90 × ×\99ת×\9f ×\9c×\94×\97×\9c×\99×£ ×\90×\95ת×\95.\n×\90×\9d ×¢×\93×\99×\99×\9f ×\91רצ×\95× ×\9a ×\9c×\94×¢×\9c×\95ת ק×\95×\91×¥ ×\96×\94, ×\99ש ×\9c×\97×\96×\95ר ×\9c×\93×£ ×\94ק×\95×\93×\9d ×\95×\9c×\94×¢×\9c×\95ת את הקובץ תחת שם חדש.\n[[File:$1|thumb|center|$1]]",
+ "fileexists-shared-forbidden": "ק×\95×\91×¥ ×\91ש×\9d ×\96×\94 ×\9b×\91ר ק×\99×\99×\9d ×\9bק×\95×\91×¥ ×\9eש×\95תף.\n×\90×\9d ×¢×\93×\99×\99×\9f ×\91רצ×\95× ×\9a ×\9c×\94×¢×\9c×\95ת ק×\95×\91×¥ ×\96×\94, ×\99ש ×\9c×\97×\96×\95ר ×\9c×\93×£ ×\94ק×\95×\93×\9d ×\95×\9c×\94×¢×\9c×\95ת את הקובץ תחת שם חדש.\n[[File:$1|thumb|center|$1]]",
"fileexists-no-change": "הקובץ שהועלה הוא העתק מדויק של הגרסה הנוכחית של <strong>[[:$1]]</strong>.",
"fileexists-duplicate-version": "הקובץ שהועלה הוא העתק מדויק של {{PLURAL:$2|גרסה קודמת|גרסאות קודמות}} של <strong>[[:$1]]</strong>.",
"file-exists-duplicate": "קובץ זה זהה {{PLURAL:$1|לקובץ הבא|לקבצים הבאים}}:",
"file-deleted-duplicate": "קובץ זהה לקובץ זה ([[:$1]]) נמחק בעבר.\nיש לבדוק את היסטוריית המחיקה של הקובץ לפני העלאתו מחדש.",
"file-deleted-duplicate-notitle": "קובץ זהה לקובץ זה נמחק בעבר, והכותרת שלו הועלמה.\nיש לבקש ממשתמש שיכול לראות נתונים על קבצים שהועלמו לבדוק את המצב לפני העלאת הקובץ מחדש.",
- "uploadwarning": "×\90×\96×\94רת ×\94×¢×\9c×\90ת ק×\91צ×\99×\9d",
- "uploadwarning-text": "×\90× ×\90 ×©× ×\95 ×\90ת ת×\99×\90×\95ר ×\94ק×\95×\91×¥ ש×\9c×\9e×\98×\94 ×\95× ×¡×\95 שוב.",
+ "uploadwarning": "×\90×\96×\94רת ×\94×¢×\9c×\90×\94",
+ "uploadwarning-text": "× ×\90 ×\9c×©× ×\95ת ×\90ת ת×\99×\90×\95ר ×\94ק×\95×\91×¥ ש×\9c×\9e×\98×\94 ×\95×\9c× ×¡×\95ת שוב.",
"uploadwarning-text-nostash": "יש להעלות מחדש את הקובץ, לשנות את התיאור להלן ולנסות שוב.",
"savefile": "שמירת קובץ",
"uploaddisabled": "העלאת קבצים מבוטלת.",
"copyuploaddisabled": "העלאת קבצים מכתובת URL מבוטלת.",
"uploaddisabledtext": "אפשרות העלאת הקבצים מבוטלת.",
- "php-uploaddisabledtext": "אפשרות העלאת הקבצים מבוטלת ברמת PHP. אנא בדקו את ההגדרה file_uploads.",
+ "php-uploaddisabledtext": "אפשרות העלאת הקבצים מבוטלת ברמת PHP.\nנא לבדוק את ההגדרה file_uploads.",
"uploadscripted": "הקובץ כולל קוד סקריפט או HTML שעשוי להתפרש או להתבצע בטעות על־ידי הדפדפן.",
"upload-scripted-pi-callback": "לא ניתן להעלות קובץ שמכיל את הוראת העיבוד XML-stylesheet.",
- "upload-scripted-dtd": "לא ניתן להעלות קבצי SVG שכוללים הכרזת DTD לא־סטנדרטית.",
+ "upload-scripted-dtd": "×\9c×\90 × ×\99ת×\9f ×\9c×\94×¢×\9c×\95ת ק×\95×\91צ×\99 SVG ש×\9b×\95×\9c×\9c×\99×\9d ×\94×\9bר×\96ת DTD ×\9c×\90־ס×\98× ×\93ר×\98×\99ת.",
"uploaded-script-svg": "נמצא אלמנט שאפשר לכתוב בו תסריט \"$1\" בקובץ ה־SVG שהועלה.",
"uploaded-hostile-svg": "נמצא CSS בלתי־מאובטח באלמנט style בקובץ ה־SVG שהועלה.",
"uploaded-event-handler-on-svg": "אסור להגדיר מאפייני טיפול באירועים <code dir=\"ltr\">$1=\"$2\"</code> בקובצי SVG.",
"uploaded-href-attribute-svg": "רכיבי <a> יכולים לקשר (href) רק ליעדי data: (קובץ מוטמע), http:// או https://, או מקטע (עם #, באותו מסמך). ברכיבים אחרים, כגון <image>, מותרים רק יעדי data: ומקטע. באפשרותך לנסות להטמיע תמונות בעת ייצוא קובץ ה־SVG שלך. נמצא <code dir=\"ltr\"><$1 $2=\"$3\"></code>.",
- "uploaded-href-unsafe-target-svg": "נמצא href לנתונים לא מאובטחים <code dir=\"ltr\"><$1 $2=\"$3\"></code> בקובץ ה־SVG שהועלה.",
+ "uploaded-href-unsafe-target-svg": "נמצא href לנתונים לא מאובטחים: יעד URI <code dir=\"ltr\"><$1 $2=\"$3\"></code> בקובץ ה־SVG שהועלה.",
"uploaded-animate-svg": "נמצא תג \"animate\" שיכול לשנות href באמצעות מאפיין \"from\" בצורת <code dir=\"ltr\"><$1 $2=\"$3\"></code> בקובץ ה־SVG שהועלה.",
"uploaded-setting-event-handler-svg": "הגדרת מאפייני טיפול באירועים חסומה, נמצא <code dir=\"ltr\"><$1 $2=\"$3\"></code> בקובץ ה־SVG שהועלה.",
- "uploaded-setting-href-svg": "השימוש בתג set כדי להוסיף מאפיין href לאלמנט הורה חסום.",
+ "uploaded-setting-href-svg": "השימוש בתג \"set\" כדי להוסיף מאפיין \"href\" לאלמנט הורה חסום.",
"uploaded-wrong-setting-svg": "השימוש בתג \"set\" כדי להוסיף יעד remote/data/script לכל מאפיין חסום. נמצא <code dir=\"ltr\"><set to=\"$1\"></code> בקובץ ה־SVG שהועלה.",
"uploaded-setting-handler-svg": "SVG שמגדיר את המאפיין \"handler\" עם remote/data/script חסום. נמצא <code dir=\"ltr\">$1=\"$2\"</code> בקובץ ה־SVG שהועלה.",
"uploaded-remote-url-svg": "SVG שמגדיר כל מאפיין style עם URL מרוחק חסום. נמצא <code dir=\"ltr\">$1=\"$2\"</code> בקובץ ה־SVG שהועלה.",
"uploaded-image-filter-svg": "נמצא מסנן תמונה עם URL: <code dir=\"ltr\"><$1 $2=\"$3\"></code> בקובץ ה־SVG שהועלה.",
- "uploadscriptednamespace": "ק×\95×\91×¥ ×\94â\80\8fâ\80\8fÖ«Ö¾SVG ×\94×\96×\94 ×\9b×\95×\9c×\9c ×\9eר×\97×\91 ש×\9d ×\91×\9cת×\99 חוקי \"<nowiki>$1</nowiki>\".",
+ "uploadscriptednamespace": "ק×\95×\91×¥ ×\94â\80\8fâ\80\8fÖ¾SVG ×\94×\96×\94 ×\9b×\95×\9c×\9c ×\9eר×\97×\91 ש×\9d ×\91×\9cת×\99Ö¾חוקי \"<nowiki>$1</nowiki>\".",
"uploadinvalidxml": "לא ניתן לפרש את ה־XML בקובץ שהועלה.",
"uploadvirus": "הקובץ מכיל וירוס!\nפרטים:\n<div dir=\"ltr\">$1</div>",
"uploadjava": "קובץ זה הוא קובץ ZIP שמכיל קובץ ‎.class של Java.\nהעלאת קובצי Java אסורה, כיוון שהם יכולים לגרום לעקיפת מגבלות האבטחה.",
"upload-description": "תיאור הקובץ",
"upload-options": "אפשרויות העלאה",
"watchthisupload": "מעקב אחרי קובץ זה",
- "filewasdeleted": "ק×\95×\91×¥ ×\91ש×\9d ×\96×\94 ×\9b×\91ר ×\94×\95×¢×\9c×\94 ×\91×¢×\91ר, ×\95×\9c×\90×\97ר ×\9e×\9b×\9f × ×\9e×\97ק.\n×\90× ×\90 ×\91Ö´Ö¼×\93ק×\95 ×\90ת $1 ×\9c×¤× ×\99 שת×\9eש×\99×\9b×\95 ×\9c×\94×¢×\9c×\95ת את הקובץ שנית.",
+ "filewasdeleted": "ק×\95×\91×¥ ×\91ש×\9d ×\96×\94 ×\9b×\91ר ×\94×\95×¢×\9c×\94 ×\91×¢×\91ר, ×\95×\9c×\90×\97ר ×\9e×\9b×\9f × ×\9e×\97ק.\n×\99ש ×\9c×\91×\93×\95ק ×\90ת $1 ×\9c×¤× ×\99 ×\94×¢×\9cאת הקובץ שנית.",
"filename-thumb-name": "נראה שכותרת הקובץ היא כותרת של תמונה מוקטנת (ממוזערת). יש להימנע מהעלאת תמונות ממוזערות בחזרה לאותו אתר ויקי. אם זו אינה תמונה ממוזערת, יש לתקן את שם הקובץ כך שיהיה משמעותי יותר ושלא יכלול את הקידומת של תמונה ממוזערת.",
- "filename-bad-prefix": "ש×\9d ×\94ק×\95×\91×¥ ש×\90ת×\9d ×\9e×¢×\9c×\99×\9d ×\9eת×\97×\99×\9c ×\91Ö¾<strong>\"$1\"</strong>, ש×\94×\95×\90 ש×\9d ש×\90×\99× ×\95 ×\9eת×\90ר ×\90ת ×\94ק×\95×\91×¥ ×\95×\91×\93ר×\9a כלל מוקצה אוטומטית על־ידי מצלמות דיגיטליות.\nיש לבחור שם מתאים יותר לקובץ, שיתאר את תכניו.",
+ "filename-bad-prefix": "ש×\9d ×\94ק×\95×\91×¥ ש×\91×\97רת ×\9c×\94×¢×\9c×\95ת ×\9eת×\97×\99×\9c ×\91Ö¾<strong>\"$1\"</strong>, ש×\94×\95×\90 ש×\9d ש×\90×\99× ×\95 ×\9eת×\90ר ×\90ת ×\94ק×\95×\91×¥ ×\95×\91×\93ר×\9aÖ¾כלל מוקצה אוטומטית על־ידי מצלמות דיגיטליות.\nיש לבחור שם מתאים יותר לקובץ, שיתאר את תכניו.",
"filename-prefix-blacklist": " #<!-- נא להשאיר שורה זו בדיוק כפי שהיא --> <pre>\n# התחביר הוא כדלקמן:\n# * כל דבר מתו \"#\" לסוף השורה הוא הערה\n# * כל שורה לא ריקה היא קידומת לשמות קבצים טיפוסיים שמצלמות דיגיטליות נותנות אוטומטית\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # מספר טלפונים סלולריים\nIMG # כללי\nJD # Jenoptik\nMGP # Pentax\nPICT # שונות\n #</pre> <!-- נא להשאיר שורה זו בדיוק כפי שהיא -->",
"upload-proto-error": "פרוטוקול שגוי",
- "upload-proto-error-text": "בהעלאה מרוחקת, יש להשתמש בכתובות URL המתחילות עם <code>http://</code> או <code>ftp://</code>.",
+ "upload-proto-error-text": "בהעלאה מרוחקת, יש להשתמש בכתובות URL המתחילות עם <code dir=\"ltr\">http://</code> או עם <code dir=\"ltr\">ftp://</code>.",
"upload-file-error": "שגיאה פנימית",
- "upload-file-error-text": "ש×\92×\99×\90×\94 ×¤× ×\99×\9e×\99ת ×\94תר×\97ש×\94 ×\91עת ×\94× ×\99ס×\99×\95×\9f ×\9c×\99צ×\95ר ק×\95×\91×¥ ×\96×\9e× ×\99 ×¢×\9c ×\94שרת.\n×\90× ×\90 צר×\95 קשר עם [[Special:ListUsers/sysop|מפעיל מערכת]].",
+ "upload-file-error-text": "ש×\92×\99×\90×\94 ×¤× ×\99×\9e×\99ת ×\94תר×\97ש×\94 ×\91עת ×\94× ×\99ס×\99×\95×\9f ×\9c×\99צ×\95ר ק×\95×\91×¥ ×\96×\9e× ×\99 ×¢×\9c ×\94שרת.\n× ×\90 ×\9c×\99צ×\95ר קשר עם [[Special:ListUsers/sysop|מפעיל מערכת]].",
"upload-misc-error": "שגיאת העלאה בלתי ידועה",
- "upload-misc-error-text": "שגיאת העלאה בלתי ידועה התרחשה במהלך ההעלאה.\nאנא ודאו שכתובת ה־URL תקינה וזמינה ונסו שוב.\nאם הבעיה חוזרת על עצמה, אנא צרו קשר עם [[Special:ListUsers/sysop|מפעיל מערכת]].",
+ "upload-misc-error-text": "שגיאת העלאה בלתי־ידועה התרחשה במהלך ההעלאה.\nנא לוודא שכתובת ה־URL תקינה וזמינה ולנסות שוב.\nאם הבעיה חוזרת על עצמה, יש ליצור קשר עם [[Special:ListUsers/sysop|מפעיל מערכת]].",
"upload-too-many-redirects": "הכתובת מכילה הפניות רבות מדי",
"upload-http-error": "התרחשה שגיאת HTTP: $1",
"upload-copy-upload-invalid-domain": "העלאת קבצים משרת זה אינה אפשרית.",
"upload-form-label-infoform-categories": "קטגוריות",
"upload-form-label-infoform-date": "תאריך",
"upload-form-label-own-work-message-generic-local": "ההעלאה מבוצעת בהתאם לתנאי השירות ולמדיניות הרישיונות ב{{grammar:תחילית|{{SITENAME}}}}.",
- "upload-form-label-not-own-work-message-generic-local": "אם אין באפשרותך להעלות את הקובץ הזה לפי המדיניות של {{SITENAME}}, עליך לסגור את התיבה הנוכחית ולנסות שיטה אחרת.",
+ "upload-form-label-not-own-work-message-generic-local": "אם אין באפשרותך להעלות את הקובץ הזה לפי המדיניות של {{SITENAME}}, {{GENDER:|עליך|עלייך}} לסגור את התיבה הנוכחית ולנסות שיטה אחרת.",
"upload-form-label-not-own-work-local-generic-local": "באפשרותך לנסות להשתמש ב[[Special:Upload|דף ברירת המחדל להעלאת קבצים]].",
"upload-form-label-own-work-message-generic-foreign": "ידוע לי שאני מעלה את הקובץ הזה למאגר משותף. ההעלאה מבוצעת בהתאם לתנאי השירות ולמדיניות הרישיונות שם.",
- "upload-form-label-not-own-work-message-generic-foreign": "אם אין באפשרותך להעלות את הקובץ הזה לפי המדיניות של המאגר המשותף, עליך לסגור את התיבה הנוכחית ולנסות שיטה אחרת.",
+ "upload-form-label-not-own-work-message-generic-foreign": "אם אין באפשרותך להעלות את הקובץ הזה לפי המדיניות של המאגר המשותף, {{GENDER:|עליך|עלייך}} לסגור את התיבה הנוכחית ולנסות שיטה אחרת.",
"upload-form-label-not-own-work-local-generic-foreign": "באפשרותך לנסות להשתמש ב[[Special:Upload|דף העלאת הקבצים ב{{grammar:תחילית|{{SITENAME}}}}]], אם ניתן להעלות את הקובץ הזה לשם לפי מדיניות האתר.",
"backend-fail-stream": "לא הייתה אפשרות להזרים את הקובץ \"$1\".",
"backend-fail-backup": "לא הייתה אפשרות לגבות את הקובץ \"$1\".",
"uploadstash": "סליק העלאות",
"uploadstash-summary": "דף זה מאפשר גישה לקבצים שהועלו (או נמצאים בתהליך העלאה), אך טרם פורסמו באתר הוויקי. קבצים אלה אינם גלויים לאיש מלבד המשתמש שהעלה אותם.",
"uploadstash-clear": "מחיקת הקבצים בסליק",
- "uploadstash-nofiles": "×\90×\99×\9f ×\9c×\9b×\9d קבצים בסליק.",
- "uploadstash-badtoken": "×\91×\99צ×\95×¢ ×\94פע×\95×\9c×\94 × ×\9bש×\9c, ×\90×\95×\9c×\99 ×\91×\92×\9c×\9c פק×\99עת ת×\95קפ×\95 ש×\9c ×\90ס×\99×\9e×\95×\9f ×\94ער×\99×\9b×\94 ש×\9c×\9b×\9d. נא לנסות שוב.",
+ "uploadstash-nofiles": "×\90×\99×\9f ×\9c×\9a קבצים בסליק.",
+ "uploadstash-badtoken": "×\91×\99צ×\95×¢ ×\94פע×\95×\9c×\94 × ×\9bש×\9c, ×\90×\95×\9c×\99 ×\91×\92×\9c×\9c פק×\99עת ת×\95קפ×\95 ש×\9c ×\90ס×\99×\9e×\95×\9f ×\94ער×\99×\9b×\94 ש×\9c×\9a. נא לנסות שוב.",
"uploadstash-errclear": "מחיקת הקבצים נכשלה.",
"uploadstash-refresh": "רענון רשימת הקבצים",
"uploadstash-thumbnail": "הצגת תמונה ממוזערת",
"uploadstash-zero-length": "הקובץ באורך אפס.",
"invalid-chunk-offset": "היסט גוש לא תקין",
"img-auth-accessdenied": "הגישה נדחתה",
- "img-auth-nopathinfo": "PATH_INFO ×\97סר.\n×\94שרת ×\90×\99× ×\95 ×\9e×\95×\92×\93ר ×\9c×\94×¢×\91רת ×\9e×\99×\93×¢ ×\96×\94.\n×\99×\99ת×\9b×\9f ש×\94×\95×\90 ×\9e×\91×\95סס ×¢×\9c CGI ×\95×\9c×\9b×\9f ×\90×\99× ×\95 ×\99×\9b×\95×\9c ×\9cת×\9e×\95×\9a ×\91Ö¾img_auth.\nר×\90×\95 https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
+ "img-auth-nopathinfo": "PATH_INFO ×\97סר.\n×\94שרת ×\90×\99× ×\95 ×\9e×\95×\92×\93ר ×\9c×\94×¢×\91רת ×\9e×\99×\93×¢ ×\96×\94.\n×\99×\99ת×\9b×\9f ש×\94×\95×\90 ×\9e×\91×\95סס ×¢×\9c CGI ×\95×\9c×\9b×\9f ×\90×\99× ×\95 ×\99×\9b×\95×\9c ×\9cת×\9e×\95×\9a ×\91Ö¾img_auth.\n×\9c×\9e×\99×\93×¢ × ×\95סף: https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
"img-auth-notindir": "הנתיב המבוקש אינו בתיקיית ההעלאות שהוגדרה.",
"img-auth-badtitle": "לא ניתן ליצור כותרת תקינה מתוך \"$1\".",
- "img-auth-nologinnWL": "×\90×\99× ×\9b×\9d ×\9e×\97×\95×\91ר×\99×\9d ×\9c×\97ש×\91×\95×\9f והדף \"$1\" אינו ברשימה המותרת.",
+ "img-auth-nologinnWL": "×\9c×\90 × ×\9b× ×¡×ª ×\9c×\97ש×\91×\95×\9f, והדף \"$1\" אינו ברשימה המותרת.",
"img-auth-nofile": "הקובץ \"$1\" אינו קיים.",
- "img-auth-isdir": "×\90ת×\9d ×\9e× ×¡×\99×\9d לגשת לתיקייה \"$1\".\nרק גישה לקבצים מותרת.",
- "img-auth-streaming": "×\9e×\91צע הזרמה של \"$1\".",
+ "img-auth-isdir": "× ×\99ס×\99ת לגשת לתיקייה \"$1\".\nרק גישה לקבצים מותרת.",
+ "img-auth-streaming": "×\9eת×\91צעת הזרמה של \"$1\".",
"img-auth-public": "img_auth.php משמש להצגת קבצים מתוך אתר ויקי פרטי.\nאתר ויקי זה מוגדר כציבורי.\nכדי להשיג אבטחה מרבית, img_auth.php מבוטל.",
"img-auth-noread": "למשתמש אין הרשאה לקרוא את \"$1\".",
"http-invalid-url": "כתובת URL בלתי תקינה: $1",
"http-curl-error": "שגיאה בקבלת כתובת ה־URL: $1",
"http-bad-status": "הייתה בעיה בשליחת בקשת ה־HTTP: $1 $2",
"upload-curl-error6": "לא ניתן להגיע ל־URL",
- "upload-curl-error6-text": "×\9c×\90 × ×\99ת×\9f ×\9c×\9bת×\95×\91ת ×\94Ö¾URL ×©× ×\9bת×\91×\94. ×\90× ×\90 ×\91×\93ק×\95 אם כתובת זו נכונה ואם האתר זמין.",
+ "upload-curl-error6-text": "×\9c×\90 × ×\99ת×\9f ×\9c×\94×\92×\99×¢ ×\9c×\9bת×\95×\91ת ×\94Ö¾URL ×©× ×\9bת×\91×\94.\n×\99ש ×\9c×\91×\93×\95ק אם כתובת זו נכונה ואם האתר זמין.",
"upload-curl-error28": "הסתיים זמן ההמתנה להעלאה",
- "upload-curl-error28-text": "לאתר לקח זמן רב מדי לענות. אנא בדקו שהאתר זמין, המתינו מעט ונסו שוב. ייתכן שתרצו לנסות בזמן פחות עמוס.",
+ "upload-curl-error28-text": "לאתר לקח זמן רב מדי לענות.\nנא לבדוק שהאתר זמין, להמתין מעט ולנסות שוב.\nייתכן שכדאי לנסות בזמן פחות עמוס.",
"license": "רישיון:",
"license-header": "רישיון",
- "nolicense": "×\90×\99×\9f",
+ "nolicense": "×\9c×\90 × ×\91×\97ר",
"licenses-edit": "עריכת אפשרויות רישיון",
"license-nopreview": "(תצוגה מקדימה לא זמינה)",
"upload_source_url": "(קובץ שבחרת מכתובת URL תקינה ונגישה לציבור)",
"savechanges": "Sačuvaj stranicu",
"publishpage": "Objavi stranicu",
"publishchanges": "Sačuvaj uređivanje",
+ "savearticle-start": "Sačuvaj stranicu...",
+ "savechanges-start": "Spremi promjene...",
+ "publishpage-start": "Objavi stranicu...",
+ "publishchanges-start": "Sačuvaj uređivanje...",
"preview": "Pregled kako će stranica izgledati",
"showpreview": "Prikaži kako će izgledati",
"showdiff": "Prikaži promjene",
"accmailtext": "Nova zaporka za [[User talk:$1|$1]] je poslana na $2.\n\nNakon prijave, zaporka za ovaj novi račun može biti promijenjena na stranici ''[[Special:ChangePassword|promijeni zaporku]]'' nakon prijave.",
"newarticle": "(Novo)",
"newarticletext": "Došli ste na stranicu koja još ne postoji.\nAko želite stvoriti tu stranicu, počnite tipkati u prozor ispod ovog teksta (pogledajte [$1 stranicu za pomoć]).\nAko ste ovamo dospjeli slučajno, kliknite gumb '''natrag''' (back) u svom pregledniku.",
- "anontalkpagetext": "----''Ovo je stranica za razgovor s neprijavljenim suradnikom koji još nije otvorio suradnički račun ili se njime ne koristi. Zbog toga se moramo služiti brojčanom IP adresom kako bismo ga identificirali. Takvu adresu često može dijeliti više ljudi. Ako ste neprijavljeni suradnik i smatrate da su Vam upućeni irelevantni komentari, molimo Vas da [[Special:CreateAccount|otvorite suradnički račun]] ili [[Special:UserLogin|se prijavite]] te tako u budućnosti izbjegnete zamjenu s drugim neprijavljenim suradnicima.''",
+ "anontalkpagetext": "----\n<em>Ovo je stranica za razgovor s neprijavljenim suradnikom koji još nije otvorio suradnički račun ili se njime ne koristi.</em>\nZbog toga se moramo služiti brojčanom IP adresom kako bismo ga identificirali. \nTakvu adresu često može dijeliti više ljudi. \nAko ste neprijavljeni suradnik i smatrate da su Vam upućeni irelevantni komentari, molimo Vas da [[Special:CreateAccount|otvorite suradnički račun]] ili [[Special:UserLogin|se prijavite]] te tako u budućnosti izbjegnete zamjenu s drugim neprijavljenim suradnicima.",
"noarticletext": "Na ovoj stranici trenutačno nema sadržaja.\nMožete [[Special:Search/{{PAGENAME}}|potražiti ovaj naslov]] na drugim stranicama,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti povezane evidencije]\nili [{{fullurl:{{FULLPAGENAME}}|action=edit}} stvoriti ovu stranicu]</span>.",
"noarticletext-nopermission": "Ova stranica nema sadržaja.\nMožete [[Special:Search/{{PAGENAME}}|tražiti naslov ove stranice]] na drugim stranicama ili <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} pretražiti povezane evidencije]</span>, ali ne možete stvoriti ovu stranicu.",
"missing-revision": "Uređivanje broj $1 na stranici \"{{FULLPAGENAME}}\" ne postoji.\n\nOvo je obično uzrokovano kada kliknete na zastarjelu poveznicu na stranice koja je obrisana.\nViše informacija možete pronaći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} evidenciji brisanja].",
"filepage-nofile-link": "Ne postoji datoteka s ovim imenom, ali možete je [$1 postaviti].",
"uploadnewversion-linktext": "Postavi novu inačicu datoteke",
"shared-repo-from": "s projekta $1",
- "shared-repo": "zajednički poslužitelj",
+ "shared-repo": "Zajednički poslužitelj",
"shared-repo-name-wikimediacommons": "Zajednički poslužitelj",
"upload-disallowed-here": "Ne možete prepisati ovu datoteku.",
"filerevert": "Ukloni ← $1",
"default": "alapértelmezett",
"prefs-files": "Fájlok",
"prefs-custom-css": "saját CSS",
+ "prefs-custom-json": "saját JSON",
"prefs-custom-js": "saját JS",
"prefs-common-config": "Közös CSS/JSON/JS az összes felület számára:",
"prefs-reset-intro": "Ezen a lapon állíthatod vissza a beállításaidat az oldal alapértelmezett értékeire.\nA műveletet nem lehet visszavonni.",
"prefs-dateformat": "Dátumformátum",
"prefs-timeoffset": "Időeltérés",
"prefs-advancedediting": "Általános",
+ "prefs-developertools": "Fejlesztői eszközök",
"prefs-editor": "Szerkesztő",
"prefs-preview": "Előnézet",
"prefs-advancedrc": "Haladó beállítások",
"fix-double-redirects": "Az eredeti címre mutató hivatkozások frissítése",
"move-leave-redirect": "Átirányítás készítése a régi címről az új címre",
"protectedpagemovewarning": "'''Figyelem:''' Ez a lap le van védve, így csak adminisztrátori jogosultságokkal rendelkező szerkesztők nevezhetik át.\nA legutolsó ide vonatkozó naplóbejegyzés alább látható:",
- "semiprotectedpagemovewarning": "'''Figyelem:''' Ez a lap le van védve, így csak regisztrált felhasználók nevezhetik át.\nA legutolsó ide vonatkozó naplóbejegyzés alább látható:",
+ "semiprotectedpagemovewarning": "<strong>Figyelem:</strong> Ez a lap le van védve, így csak regisztrált felhasználók nevezhetik át.\nA legutolsó ide vonatkozó naplóbejegyzés alább látható:",
"move-over-sharedrepo": "A(z) [[:$1]] néven már létezik fájl egy megosztott tárhelyen. Ha ilyen néven töltöd fel, el fogja takarni a közös tárhelyen levőt.",
"file-exists-sharedrepo": "A választott fájlnév már használatban van egy közös tárhelyen.\nKérlek válassz másik nevet.",
"export": "Lapok exportálása",
"Irus",
"Narek",
"23artashes",
- "Fitoschido"
+ "Fitoschido",
+ "Սահակ"
]
},
"tog-underline": "ընդգծել հղումները՝",
"copyrightpage": "{{ns:project}}:Հեղինակային իրավունքներ",
"currentevents": "Ընթացիկ իրադարձություններ",
"currentevents-url": "Project:Ընթացիկ իրադարձություններ",
- "disclaimers": "Ազատում պատասխանատվությունից",
+ "disclaimers": "Հրաժարագրեր",
"disclaimerpage": "Project:Ազատում պատասխանատվությունից",
"edithelp": "Խմբագրման ուղեցույց",
"helppage-top-gethelp": "Օգնություն",
"recentchangeslinked-page": "Էջի անվանումը՝",
"recentchangeslinked-to": "Հակառա՛կը. ցույց տալ այս էջին հղող էջերի փոփոխությունները։",
"recentchanges-page-added-to-category": "[[:$1]] էջը ավելացվել է կատեգորիայում",
- "upload": "Բեռնել նիշք (ֆայլ)",
+ "upload": "Բեռնել նիշք",
"uploadbtn": "Բեռնել նիշք",
"reuploaddesc": "Վերադառնալ բեռնման ձևին։",
"uploadnologin": "Դուք չեք մտել համակարգ",
"아라"
]
},
- "tog-underline": "Okpürụ ahiri jikodo:",
+ "tog-underline": "Ahịrịàlà òjikọ:",
"tog-hideminor": "Zonari orü ntàkírí na nwerue mẹrẹ ogẹ nsó",
"tog-hidepatrolled": "Zonari orü ha hụrụ na nwerue mẹrẹ ogẹ nsó",
"tog-newpageshidepatrolled": "Zonari orü ha hụrụ shí ndetu ihü ohúrù",
"tog-diffonly": "É zìkwàlà ihe nọr na ihü di okpúrù íchiè",
"tog-showhiddencats": "Zi ébéonọr zonari a zonari",
"tog-norollbackdiff": "Kwà diff mgbe byárá na mgbe láázú mèchàrà",
- "underline-always": "Ngbẹowula",
- "underline-never": "Anáobulạ",
+ "underline-always": "M̀gbèọbụlà",
+ "underline-never": "Emelaème",
"underline-default": "Ndatụ ihü njikota",
"editfont-style": "Rüwa ámá udị mkpúrù èdè:",
"editfont-monospace": "Otụ ihe ná kechí mkpúrù èdè",
"editfont-sansserif": "Mkpúrù èdè sans-serif",
"editfont-serif": "Mkpúrù èdè Serif",
- "sunday": "Sondè",
- "monday": "Mondè",
- "tuesday": "Tusdè",
- "wednesday": "Wensdè",
- "thursday": "Torsdè",
- "friday": "Fridè",
- "saturday": "Satorde",
- "sun": "Son",
- "mon": "Mon",
- "tue": "Tus",
- "wed": "Wen",
- "thu": "Tor",
- "fri": "Fri",
- "sat": "Sat",
- "january": "Önwa Mbú",
- "february": "Önwa Abụọ",
- "march": "Önwa Atọ",
- "april": "Önwa Anọ",
- "may_long": "Önwa Ise",
- "june": "Önwa Isii",
- "july": "Önwa Asaa",
- "august": "Önwa Asáto",
- "september": "Önwa Itolu",
- "october": "Önwa Iri",
- "november": "Önwa Iri na otu",
- "december": "Önwa Iri na abụọ",
- "january-gen": "Önwa Mbú",
- "february-gen": "Önwa Abụọ",
- "march-gen": "Önwa Atọ",
- "april-gen": "Önwa Anọ",
- "may-gen": "Önwa Ise",
- "june-gen": "Önwa Isii",
- "july-gen": "Önwa Asaa",
- "august-gen": "Önwa Asatọ",
- "september-gen": "Önwa Itolu",
- "october-gen": "Önwa Iri",
- "november-gen": "Önwa Iri na otu",
- "december-gen": "Önwa Iri na abụọ",
- "jan": "ÖMbú",
- "feb": "ÖAbụ",
- "mar": "ÖAtọ",
- "apr": "ÖAnọ",
- "may": "ÖIse",
- "jun": "ÖIsi",
- "jul": "ÖAsa",
- "aug": "ÖAsọ",
- "sep": "ÖIto",
- "oct": "ÖIri",
- "nov": "ÖIrinotu",
- "dec": "ÖIrinabụọ",
- "pagecategories": "{{PLURAL:$1|Ébéonọr|Ébéonọr}}",
+ "sunday": "Èhìchim̀bụ",
+ "monday": "Èhìchiàbụọ",
+ "tuesday": "Èhìchiàtọ",
+ "wednesday": "Èhìchiànọ",
+ "thursday": "Èhìchiìse",
+ "friday": "Èhìchiìsiì",
+ "saturday": "Èhìchiọdụ̀",
+ "sun": "Chi1",
+ "mon": "Chi2",
+ "tue": "Chi3",
+ "wed": "Chi4",
+ "thu": "Chi5",
+ "fri": "Chi6",
+ "sat": "Chi7",
+ "january": "Ọnwam̀bụ",
+ "february": "Ọnwaàbụọ",
+ "march": "Ọnwaàtọ",
+ "april": "Ọnwaànọ",
+ "may_long": "Ọnwaìse",
+ "june": "Ọnwaìsiì",
+ "july": "Ọnwaàsaà",
+ "august": "Ọnwaàsatọ",
+ "september": "Ọnwaìtoolu",
+ "october": "Ọnwaìri",
+ "november": "Ọnwaìrinàotù",
+ "december": "Ọnwaìrinààbụọ",
+ "january-gen": "Ọnwam̀bụ",
+ "february-gen": "Ọnwaàbụọ",
+ "march-gen": "Ọnwaàtọ",
+ "april-gen": "Ọnwaànọ",
+ "may-gen": "Ọnwaìse",
+ "june-gen": "Ọnwaìsiì",
+ "july-gen": "Ọnwaàsaà",
+ "august-gen": "Ọnwaàsatọ",
+ "september-gen": "Ọnwaìtoolu",
+ "october-gen": "Ọnwaìri",
+ "november-gen": "Ọnwaìrinàotù",
+ "december-gen": "Ọnwaìrinààbụọ",
+ "jan": "ỌM̀bụ",
+ "feb": "ỌÀbụ",
+ "mar": "ỌÀtọ",
+ "apr": "ỌÀnọ",
+ "may": "ỌÌse",
+ "jun": "ỌÌsi",
+ "jul": "ỌÀsa",
+ "aug": "ỌÀst",
+ "sep": "ỌÌto",
+ "oct": "ỌÌri",
+ "nov": "Ọn11",
+ "dec": "Ọn12",
+ "january-date": "Ọnwam̀bụ $1",
+ "february-date": "Ọnwaàbụọ $1",
+ "march-date": "Ọnwaàtọ $1",
+ "april-date": "Ọnwaànọ $1",
+ "may-date": "Ọnwaìse $1",
+ "june-date": "Ọnwaìsiì $1",
+ "july-date": "Ọnwaàsaà $1",
+ "august-date": "Ọnwaàsatọ $1",
+ "september-date": "Ọnwaìtoolu $1",
+ "october-date": "Ọnwaìri $1",
+ "november-date": "Ọnwaìrinàotù $1",
+ "december-date": "Ọnwaìrinààbụọ",
+ "pagecategories": "{{PLURAL:$1|Ụdàkọ}}",
"category_header": "Ihü nọr ime ébéonọr \"$1\"",
- "subcategories": "Ébéonọr ime ime",
+ "subcategories": "Ụdàkọòkpurù",
"category-media-header": "Nka nọr ime ébéonọr \"$1\"",
"category-empty": "\"Ébéonọr nke enwéghị ihü ma nkà ímé ya.\"",
- "hidden-categories": "{{PLURAL:$1|Ébéonọr zonari|Ébéonọr zonari}}",
+ "hidden-categories": "{{PLURAL:$1|Ụdàkọ nzezò}}",
"hidden-category-category": "Ébéanọr zonari a zonari",
"category-subcat-count": "{{PLURAL:$2|Ébéanọr nka nwerechạ ébéanọr-ime nkeá.|Ébéanọr nka nwere {{PLURAL:$1|ébéanọr-ime|$1 ébéanọr-ime}}, guru nke $2 total.}}",
"category-subcat-count-limited": "Ébéonọr nke á nwèrè {{PLURAL:$1|íméébéanọr|íméébéanọr $1}} nke á.",
"category-article-count-limited": "Nkeá {{PLURAL:$1|ihü dị|ihü $1 dị}} na ébéanọr nkeá.",
"category-file-count": "{{PLURAL:$2|Ébéonọr nka nwèrè náni usòrò nka.|{{PLURAL:$1|Usòrò nka|Usòrò nke $1}} di na ímé ébéonọr nga, shí háníle di $2.}}",
"category-file-count-limited": "Nkeá {{PLURAL:$1|usòrò dị|usòrò $1 dị}} na ébéanọr nkeá.",
- "listingcontinuesabbrev": "mewá.",
+ "listingcontinuesabbrev": "gàzi.",
"index-category": "Ẹdẹle Ihü",
"noindex-category": "Ihü ẹdẹlebu",
"broken-file-category": "Ihü nwere jkọdọ na ga fail gbajírí",
"about": "Màkà",
"article": "Ihü ihe dị",
"newwindow": "(o na mepo na onyonyo ohúrù)",
- "cancel": "Kàchá",
+ "cancel": "Hapụ̀",
"moredotdotdot": "Ozókwá...",
"mypage": "Ihü",
- "mytalk": "Okwu",
- "anontalk": "Owu màkà IP nká",
- "navigation": "Otú Uzọr",
+ "mytalk": "Nkàta",
+ "anontalk": "Nkàta",
+ "navigation": "Nturuụzọ̀",
"and": " ná",
"faq": "FAQ",
"actions": "Mmèmé",
- "namespaces": "Ámááhà",
+ "namespaces": "Ahàm̀bara",
"variants": "Nke ichè ichè",
"errorpagetitle": "Nsogbú",
"returnto": "Ganata na $1.",
"tagline": "Oshị {{SITENAME}}",
"help": "Inyeáká",
- "search": "Chọwa",
- "searchbutton": "Chọwa",
+ "search": "Tùwe",
+ "searchbutton": "Tùwe",
"go": "Gá",
"searcharticle": "Gá",
"history": "Ịta ihüá",
"history_short": "Ịta",
"updatedmarker": "ihe gáráníru ké mgbe m byàrà nga mbu",
- "printableversion": "Nkè I nweríkí dotié",
+ "printableversion": "Ùdì ǹke mbifụ̀",
"permalink": "Jikodo ekechịrị",
"print": "Dotié",
"view": "Lèzí",
+ "view-foreign": "Zi nà $1",
"edit": "Mèzi",
"create": "Ké",
"delete": "Kàcha",
"protect_change": "gbanwe",
"unprotect": "Nchẹdo mgbanwe",
"newpage": "Ihü ohúrù",
- "talkpagelinktext": "Okwu",
+ "talkpagelinktext": "nkàta",
"specialpage": "Ihü mkpà",
- "personaltools": "Ngwa nkem",
- "talk": "Akíkó",
+ "personaltools": "Ngwa ọrụ ònwe",
+ "talk": "Nkpata okà",
"views": "Há hụrụ ya olé",
- "toolbox": "Ngwa Oru",
- "imagepage": "Zi ihü usòrò",
- "mediawikipage": "Zi ihü ozi",
- "templatepage": "Zi ihü nkpurụ ihü",
- "viewhelppage": "Zi ihü I nye áká",
- "categorypage": "Zi ébé ihü nọr",
- "viewtalkpage": "Zi akíkó",
- "otherlanguages": "Na asụsụ ndị ozó",
- "redirectedfrom": "(Kufùrù shi $1)",
+ "toolbox": "Ngwa ọrụ",
+ "imagepage": "Zìri ihu àfabà",
+ "mediawikipage": "Zìri ihunde ozi",
+ "templatepage": "Zìri ihunde àtụ̀",
+ "viewhelppage": "Zìri ihu nkwàdo",
+ "categorypage": "Zìri ihu ụdàkọ",
+ "viewtalkpage": "Zìri nkàta",
+ "otherlanguages": "Nà asụ̀sụ̀ ndị ọ̀zọ",
+ "redirectedfrom": "(Dupụ̀rụ̀ sì $1)",
"redirectpagesub": "Kufù ebe ihü nka na ga",
"lastmodifiedat": "Há rüchàrà na ihü nka na $1, mgbe $2",
"viewcount": "Ha banyere ihü nka na {{PLURAL:$1|otu|$1 mgbe ole}}.",
"protectedpage": "Ihü a cẹdolu a cẹdo",
- "jumpto": "Wuá ébé:",
- "jumptonavigation": "otú uzọr",
- "jumptosearch": "chọwa",
+ "jumpto": "Wụ̀ ga:",
+ "jumptonavigation": "nturuụzọ̀",
+ "jumptosearch": "tùwe",
"view-pool-error": "Ndó, ihe na enye juchàrà ejucha oge nka.\nMadu kachạrạ ndi choro ihu ihü nka.\nBiko chetukwa oge kà oruo mgbe I choro I banyé ihü nka ozor.\n\n$1",
"pool-timeout": "Ógè e zuole Í ché ncedọ",
"pool-queuefull": "Pool kyu zùrù",
"pool-errorunknown": "Nsogbu nke námaghi",
- "aboutsite": "Maka {{SITENAME}}",
- "aboutpage": "Project:Ihe owù",
+ "aboutsite": "Màkà {{SITENAME}}",
+ "aboutpage": "Project:Màkà",
"copyright": "Ihe di ime nọr okpúrụ $1",
"copyrightpage": "{{ns:project}}:Iwu maka ijë ihe",
"currentevents": "Ihe ne me ubuwá",
"currentevents-url": "Project:I ne me ubüwá",
- "disclaimers": "Ihe anyí chọrọ ki ma",
+ "disclaimers": "Ńwefụ̀aka",
"disclaimerpage": "Project:Ihe I kweshiri ma",
"edithelp": "Inyetuáká I rüwa",
- "mainpage": "Ihü Mbu",
- "mainpage-description": "Ihü Mbu",
+ "mainpage": "Ihu m̀bụ",
+ "mainpage-description": "Ihu m̀bụ",
"policy-url": "Project:Iwu",
"portal": "Ogbako ọtú",
"portal-url": "Project:Ogbako Ọtú",
- "privacy": "Iwu maka ndi ichi ichie",
- "privacypage": "Project:Iwu maka ndi ichi ichie",
+ "privacy": "Ụmẹzù ǹzuzo",
+ "privacypage": "Project:Ụmẹzù ǹzuzo",
"badaccess": "Nsogbu ébé ha na nyé ike I bàtá",
"badaccess-group0": "I nwéghị ọdà Í kpárá ihe Í chọrí mė.",
"badaccess-groups": "Ihe Í chọrí me bu ihe ndi ọ'bànifé nke ntàkírí nọr na {{PLURAL:$2|the group|ótù ọtú}} ne me náni: $1",
"viewsourceold": "zi mkpurụ",
"editlink": "mèzi",
"viewsourcelink": "zi mkpurụ",
- "editsectionhint": "Rüwa na élu nkeji: $1",
+ "editsectionhint": "Mèzi òkè: $1",
"toc": "Ihe dị ime",
"showtoc": "zi",
"hidetoc": "zonari",
"site-atom-feed": "$1 ntabì Atom",
"page-rss-feed": "''$1'' ntabì RSS",
"page-atom-feed": "''$1'' ntabì Atom",
- "red-link-title": "$1 (ihü a di gì)",
+ "red-link-title": "$1 (ihu a dị gị̀)",
"sort-descending": "Dozi shí àlà",
"sort-ascending": "Dozi shí élú",
"nstab-main": "Ihü",
- "nstab-user": "Ihü ọ'bànifé",
+ "nstab-user": "Ihunde òjìème",
"nstab-media": "Ihü nkà",
"nstab-special": "Ihü mkpà",
"nstab-project": "Ihü orürü",
- "nstab-image": "Usòrò",
+ "nstab-image": "Àfabà",
"nstab-mediawiki": "Ozi",
"nstab-template": "Àtụ",
"nstab-help": "Ihü ebe ha na nye áká",
- "nstab-category": "Ébéonọr",
+ "nstab-category": "Ụdàkọ",
+ "mainpage-nstab": "Ihu m̀bụ",
"nosuchaction": "Mmèmé adighi",
"nosuchactiontext": "Ihe URL chọrọ Í me àdíghị ézíbóté.\nÍ nwèríkí dèfié URL è dèfie, ma ó nwèríkí bụ nà Í sọrọ jikodo nke àdíghị mma.\nIhe a nwèríkí bu ihe ne zi bug di na ngwa nsónùsòrò nke {{SITENAME}} jì à rü.",
"nosuchspecialpage": "Ihü mkpà nka a nogị",
"badtitletext": "Íshí ihü Í chọrọ à díghị ézíbóté, efù, mà ȯ dị jikodo di jikodo nke ojö na nke íshí asụsụ-mmékotárí ma wiki-mmékotárí.\nO nwèríkí nwé édé ótù ma nke ozor nke ékwéghị na íshí ihü.",
"perfcached": "Ómárí á kachẹrẹ na o nwẹrẹ ki a kugwaghị ya na ogẹ di nso. A maximum of {{PLURAL:$1|one result is|$1 results are}} available in the cache.",
"viewsource": "Zi mkpurụ",
+ "viewsource-title": "Zi mkpụrụ $1",
"actionthrottled": "Mmèmé a puziélé",
"protectedpagetext": "Ihüá cedolụ maka orürü ạ gáa bá.",
"viewsourcetext": "Í nwèríkí lé na Í jé mkpurụ ihüá:",
"virus-scanfailed": "ojëjë orunotụ dàrà (edemede $1)",
"virus-unknownscanner": "amaghị obubu onyá:",
"logouttext": "'''I fwuóla ubwá.'''\n\nI nwèríkí jíwá {{SITENAME}} na nke ẹnwéghi áhà, mànà Í nwèríkí <span class='plainlinks'>[$1 bátá òzọr]</span> na áhà Í shị fwüo ma áhà ozọr.\nMàkwá na o dị ihü gi zi kà Í nor kwa ímé, o gi kwüshí mgbe Í sáfùrù cache ihe ishi a gá intanet gi.",
- "yourname": "Áhà ọ'bànifé:",
+ "yourname": "Ahàǹjìème:",
+ "userlogin-yourname": "Ahàǹjìème",
"yourpassword": "Okwúngáfè:",
+ "userlogin-yourpassword": "Okwungafè",
"yourpasswordagain": "Detuari mkpurụ okwu ejị a gafẹ:",
"yourdomainname": "Obí gi:",
- "login": "Banyé",
+ "login": "Detùba",
"nav-login-createaccount": "Banyé / ké buwá",
"logout": "Fwuör",
"userlogout": "Fwuör",
"notloggedin": "I bátà bò",
"createaccount": "Ké otụ buwa",
"createaccountmail": "na e-mail",
+ "createacct-benefit-body1": "{{PLURAL:$1|ḿmezi}}",
"badretype": "Mkpurụ okwu ejị a gafẹ é jëghị.",
"userexists": "Áhè ọ'bànifé tírí di na áká onye ozor.\nBíkó nwèré áhà nke ozor.",
"loginerror": "Nsogbu ngbe I choro I bata",
"accountcreated": "Ndoté è mepólé",
"createaccount-title": "Okìké bùwá màkà {{SITENAME}}",
"loginlanguagelabel": "Asụsụ: $1",
+ "pt-login": "Debàta",
+ "pt-createaccount": "Kèta ngụrụòkè",
"changepassword": "Gbanwe okwu éjị à gáfe",
"resetpass_header": "Gbanwe okwúngáfè nke bùwá",
"oldpassword": "Mkpurụ okwu ejị a gafẹ ochië:",
"retypenew": "Dechákwari mkpurụ okwu ejị a gafẹ nke ohúrù:",
"resetpass_submit": "Bá okwu éjị gáfè na áhà Í bànyè",
"changepassword-success": "Mkpurụ okwu ejị a gafẹ a gbanwere nke oma!\nI na á banye...",
+ "botpasswords-label-cancel": "Hapụ̀",
"resetpass_forbidden": "Okwu éjị à gáfè enwéghịkị gabnwe",
"resetpass-submit-loggedin": "Gbanwe okwu éjị à gáfe",
- "resetpass-submit-cancel": "Kàchá",
+ "resetpass-submit-cancel": "Hapụ̀",
"resetpass-temp-password": "mkpurụ okwu ejị a gafẹ I gi kushi ngwa ngwa:",
"passwordreset": "Nkuwaria okwúngáfè",
+ "passwordreset-username": "Ahàǹjìème:",
"passwordreset-emailelement": "Áhà Ọ'banife: \n$1\n\nPasswod nke gi gbanwe: \n$2",
"changeemail-none": "(efù)",
"bold_sample": "Mkpúrù èdè íke",
"subject": "Ihe gbasara/Ishi ahiri",
"minoredit": "Ihe bu orü ntakírí",
"watchthis": "Lèwá ihüá",
- "savearticle": "Domá ihüa",
+ "savearticle": "Dònye ihuâ",
"preview": "Lètú",
- "showpreview": "Létu ntakìrí",
- "showdiff": "Zi ihe gbanwere",
+ "showpreview": "Zìwe nkirimaàtụ̀",
+ "showdiff": "Zi mgbanwè",
"anoneditwarning": "'''Kpàchákwá anya:''' Ị bághị bo.\nIP gi gí détụ na ákíkó mbu ihü a.",
"missingcommenttext": "Biko tinyé ótù okwu na àlà nga.",
"summary-preview": "Hutukwá mmẹkotá:",
"history-title": "Ákíkó mbu màkà orü nọr na élú \"$1\"",
"lineno": "Ahiri $1:",
"compareselectedversions": "Sikwụ orü áká dị",
- "editundo": "mẹ̀rí àzụ́",
- "searchresults": "Ndọfùtà nchọwa",
+ "editundo": "mè la àzụ",
+ "searchresults": "Nchọfụ̀ta",
"searchresults-title": "Ihe futárá nchowá màkà ''$1''",
"titlematches": "Íshí ihü dàbànyèrè",
"textmatches": "Mkpụrụ édémédé nwèrè ihü ȯ dị na",
"shown-title": "Zí $1 {{PLURAL:$1|ihe fútárá|ihe fútárá}} na ótù ihü",
"viewprevnext": "Lé ($1 {{int:pipe-separator}} $2) ($3)",
"searchmenu-new": "'''Ké ihü \"[[:$1]]\" na wiki nke á!'''",
- "searchprofile-articles": "Ihü ihe dị",
- "searchprofile-images": "Nkaníle",
- "searchprofile-everything": "Iheníle",
- "searchprofile-advanced": "Nke kárí",
- "searchprofile-articles-tooltip": "Chọwa na $1",
- "searchprofile-images-tooltip": "Chọwa màkà usòrò",
- "searchprofile-everything-tooltip": "Tùwé ihe nile (na okwu ihü)",
- "searchprofile-advanced-tooltip": "Chọwa na ímé áhàámá nke gí Í kèrè",
+ "searchprofile-articles": "Ihu ịhe dị̀",
+ "searchprofile-images": "Oke-ǹkà",
+ "searchprofile-everything": "Ịhe níle",
+ "searchprofile-advanced": "Ọ̀kàkaà",
+ "searchprofile-articles-tooltip": "Tùwe na $1",
+ "searchprofile-images-tooltip": "Chọ̀wa àfabà",
+ "searchprofile-everything-tooltip": "Tùwe ịhe níle (mà nà ihu nkàta)",
+ "searchprofile-advanced-tooltip": "Tùwe nà ime ahàm̀bara ntụziri",
"search-result-size": "$1 ({{PLURAL:$2|mkpurụ edemede 1|$2 mkpurụ edemede}})",
"search-redirect": "(kúfù $1)",
"search-section": "(nkeji $1)",
+ "search-category": "(ụdàkọ $1)",
"search-suggest": "Ị̀ kwèshirí dé: $1",
"search-interwiki-caption": "Orürü nwanne nwanyị",
"search-interwiki-default": "$1 nke ziri:",
"powersearch-togglelabel": "Lechányá:",
"powersearch-toggleall": "Haníle",
"powersearch-togglenone": "Efù",
- "preferences": "Otu ha dosẹrẹ ihe",
- "mypreferences": "Otú m shị na dose ihem",
+ "preferences": "Ndoziri",
+ "mypreferences": "Ndoziri",
"prefs-skin": "Akpụkpọ",
"skin-preview": "Lètú",
"datedefault": "Otú é shị na dose ihe efù",
- "prefs-user-pages": "Ihü ọ'bànifé",
+ "prefs-user-pages": "Ihunde òjìème",
"prefs-personal": "Nkówá ọ'bànifé",
"prefs-rc": "Mgbánwè ógè nso",
- "prefs-watchlist": "Ndétụnlé",
+ "prefs-watchlist": "Ùlìle",
"prefs-watchlist-days-max": "Maximum $1 {{PLURAL:$1|day|days}}",
"prefs-misc": "Mcheta-ma-mchetaghim",
"prefs-resetpass": "Gbanwe okwu éjị à gáfe",
"prefs-email": "Màkà e-mail",
"prefs-rendering": "Ọdịdị",
- "saveprefs": "Domá",
+ "saveprefs": "Dònye",
"prefs-editing": "Írüwa",
- "searchresultshead": "Chọwa",
+ "searchresultshead": "Tùwe",
"stub-threshold-disabled": "Ápụgị òkò",
"timezonelegend": "Nkeji ogẹ:",
"localtime": "Ogẹ ebeanọr:",
"timezoneregion-europe": "Alá Bèke",
"timezoneregion-indian": "Abwädi Ukwu India",
"timezoneregion-pacific": "Òrìmìlì Pasifik",
- "prefs-searchoptions": "Màkà nchöwa",
- "prefs-namespaces": "Áhàámá",
+ "prefs-searchoptions": "Tùwe",
+ "prefs-namespaces": "Ahàm̀bara",
"default": "nke éjị bịdó",
- "prefs-files": "Usòrò",
+ "prefs-files": "Àfabà",
"prefs-custom-css": "CSS nà áká mádu",
"prefs-custom-js": "JavaScript na áká mádu",
"youremail": "E-mail:",
- "username": "Áhà ọ'bànifé:",
+ "username": "{{GENDER:$1|Ahàǹjìème}}:",
"prefs-memberingroups": "Onyé otu nke {{PLURAL:$1|ọtú|ọtú}}:",
"yourrealname": "Ézíbóté áhà:",
"yourlanguage": "Ásụ̀sụ̀:",
"yournick": "Ndè áhà gi òhúrù:",
"yourgender": "Nwayi/okpoho ma o nwoke:",
- "gender-unknown": "Ámákwàghị",
+ "gender-unknown": "M̀gbè ha tụ̀rụ̀ gị aka, ndiriusòrò g'ị jiri okwu ụ̀dịnàètitì a kàtara èkèrè gị m̀gbè o nwèrè ike ị",
"gender-male": "Òkò",
"gender-female": "Ányị̀",
"email": "ozi e-mail",
"userrights-groupsmember": "Onye ọtú nke:",
"userrights-reason": "Mgbághapụtà:",
"group": "Ọtú:",
- "group-user": "Ọ'bànifé",
+ "group-user": "Òjìème",
"group-bot": "Bot",
"group-sysop": "Ndi íshí",
"group-bureaucrat": "Ọdọzị'obodo",
"group-suppress": "Aghọ",
"group-all": "(háníle)",
- "group-user-member": "ọ'bànifé",
+ "group-user-member": "{{GENDER:$1|òjìème}}",
"group-autoconfirmed-member": "ọ'bànifé kwé'nà'áká",
"group-bot-member": "bot",
"group-sysop-member": "onye íshí",
"group-bureaucrat-member": "ọdọzị'obodo",
"group-suppress-member": "aghọ",
- "grouppage-user": "{{ns:project}}:Ọ'bànifé",
+ "grouppage-user": "{{ns:project}}:Òjìème",
"grouppage-bot": "{{ns:project}}:Bot",
"grouppage-sysop": "{{ns:project}}:Ndi Íshí wiki",
"right-read": "Gụwá ihü",
"right-edit": "Rüwa ihü",
"right-createpage": "Ké ihü (nke nadíghị na ihü okwu)",
- "right-move": "Páfù ihü",
- "right-movefile": "Páfù usòrò",
+ "right-move": "Papụ̀ ihuâ",
+ "right-movefile": "Papụ̀ àfabà",
"right-upload": "Tịnyé ihe na nsónùsòrò",
"right-delete": "Kàchafu ihü",
"right-bigdelete": "Kàcha ihü nwéré ákíkó mbu dí ógólógó",
"newuserlogpage": "Ndétu nchétá ihe ọ'bànifé kèrè",
"rightslog": "Ndetu échìchè íwú ọ'bànifé",
"action-read": "guwa ihüá",
- "action-edit": "rüo élu ihüá",
+ "action-edit": "mèzi ihu â",
"action-createpage": "ké ihü",
- "action-move": "puzié ihü nke",
+ "action-move": "papụ̀ ihuâ",
"action-movefile": "puzié usòrò",
"action-upload": "tinyé njikota èdèa",
"action-reupload": "tinyé ihe ozor élu njikota èdèa",
"action-delete": "kàcha ihü nka",
"nchanges": "$1 {{PLURAL:$1|gbanwere|gbanwere}}",
+ "enhancedrc-history": "ị̀ta",
"recentchanges": "Mgbánwè ógè nso",
"recentchanges-legend": "Nràlụ màkà Ihe gbanwere ubwá",
"recentchanges-feed-description": "Chóputà ihe ógẹ ǹsò na wiki ímé órírí nke á.",
"recentchanges-label-minor": "Ihe bu orü ntakírí",
"recentchanges-legend-newpage": "$1 - ihü ohúrù",
+ "rcfilters-savedqueries-cancel-label": "Hapụ̀",
"rclistfrom": "Zìrí ihe gbanwere ọhúrù shí $3 $2",
"rcshowhideminor": "orü ntákírí $1",
+ "rcshowhideminor-show": "Zi",
+ "rcshowhideminor-hide": "Zònarị",
"rcshowhidebots": "bot $1",
+ "rcshowhidebots-show": "Zi",
+ "rcshowhidebots-hide": "Zònarị",
"rcshowhideliu": "Ndi né ké dị $1 di íme",
+ "rcshowhideliu-show": "Zi",
+ "rcshowhideliu-hide": "Zònarị",
"rcshowhideanons": "$1 ndi ọ'bànifé nke amághị",
+ "rcshowhideanons-show": "Zi",
+ "rcshowhideanons-hide": "Zònarị",
"rcshowhidepatr": "$1 orü hä lèrè",
"rcshowhidemine": "$1 ihe m rürü",
+ "rcshowhidemine-show": "Zi",
+ "rcshowhidemine-hide": "Zònarị",
"rclinks": "Zí nke mbu $1 gbawere na ubochi gárá nke $2",
- "diff": "Íchè",
+ "diff": "ichè",
"hist": "akíkómbu",
"hide": "Zonari",
"show": "Zi",
"newpageletter": "N",
"boteditletter": "b",
"number_of_watching_users_pageview": "[$1 {{PLURAL:$1|ọ'bànifé|ọ'bànifé}} ne lé anya]",
+ "rc-change-size-new": "{{PLURAL:$1|byte}} $1 ǹkè mgbanwè fọ̀rọ̀",
"newsectionsummary": "/* $1 */ nkeji ohúrù",
"rc-enhanced-expand": "Zi ihe di ime (Í gí nwere JavaScript)",
"rc-enhanced-hide": "Zonari ihe di ime",
"sourceurl": "URL mkpọlógwù:",
"upload-description": "Nkówá usòrò",
"watchthisupload": "Lèwá ákwúkwó orunotunị",
+ "upload-dialog-button-cancel": "Hapụ̀",
+ "upload-dialog-button-save": "Dònye",
+ "upload-form-label-infoform-categories": "Ụdàkọ",
"http-read-error": "Nsogbu Í gü HTTP.",
"upload-curl-error6": "Ènwéghịkị ruó URL",
"license": "Nkwényé:",
"license-header": "Nkwényé",
"nolicense": "Ọ dígì nke áká di.",
- "imgfile": "usòrò",
+ "imgfile": "àfabà",
"listfiles": "Ndétu usòrò",
"listfiles_thumb": "Nvọáká",
"listfiles_date": "Ǹgụ́ụ̀bọ̀chị̀",
"listfiles_name": "Áhà",
- "listfiles_user": "Ọ'bànifé",
+ "listfiles_user": "Òjìème",
"listfiles_size": "Ívụ",
"listfiles_description": "Nkówá",
"listfiles_count": "Ùdị",
- "file-anchor-link": "Usòrò",
+ "file-anchor-link": "Àfabà",
"filehist": "Ịta nke usòrò",
- "filehist-help": "Kpàtá na úbochi/ógè Í zí usòrò ọtụ ȯ dị mgbe áhù.",
+ "filehist-help": "Bìri èhì/ogè k'ị hụ òtù ụ̀fa dị̀ m̀gbè ahụ̀.",
"filehist-deleteall": "kàcha hanílé",
"filehist-deleteone": "kàcha",
"filehist-revert": "gbanwe lá àzú",
- "filehist-current": "nka",
- "filehist-datetime": "Afọ/Ogẹ",
- "filehist-thumb": "Nvọáká",
+ "filehist-current": "dị ùgbu â",
+ "filehist-datetime": "Èhì/Ogè",
+ "filehist-thumb": "Mbọ-aka",
"filehist-thumbtext": "NvóÁká màkà otù ȯ dị nà $1",
"filehist-nothumb": "Nvọáká adịghị",
- "filehist-user": "Ọ'bànifé",
+ "filehist-user": "Òjìème",
"filehist-dimensions": "Ógólógó na asaá",
"filehist-filesize": "Ívù usòrò",
- "filehist-comment": "Okwu-nokwu",
+ "filehist-comment": "Nkwute",
"imagelinks": "Mgbanwe usòrò",
"linkstoimage": "{{PLURAL:$1|Ihü nká|Ihü nke $1}} na jikodo gá usòrò nká:",
"nolinkstoimage": "Àdíghị ihü na jikodo usòrò nke.",
"unusedtemplates": "Àtụ hè jí gị",
"unusedtemplateswlh": "jikodo ndi ozor",
"randompage": "Edemede nkeówúlạ",
+ "randomincategory-category": "Ụdàkọ",
"randomincategory-submit": "Gá",
"statistics": "Olìlé ọtụ ihe dị",
"statistics-header-pages": "Ọmúmú-nà-ńlé ihü",
"withoutinterwiki-legend": "Na íshí mkpụrụ okwu",
"withoutinterwiki-submit": "Zi",
"nbytes": "$1 {{PLURAL:$1|byte|byte di}}",
- "ncategories": "{{PLURAL:$1|ébéonọr|ébéonọr}} $1",
+ "ncategories": "{{PLURAL:$1|ụdàkọ}} $1",
"nlinks": "{{PLURAL:$1|jikodo|jikodo}} $1",
"nmembers": "{{PLURAL:$1|ọ'bànifé|Ndi n'bànifé}} $1",
"nrevisions": "{{PLURAL:$1|orübà|orübà}} $1",
"usereditcount": "$1 {{PLURAL:$1|rüwá|orürü}}",
"usercreated": "Kéré na $1 mgbe $2",
"newpages": "Ihü ohúrù",
- "newpages-username": "Áhà ọ'bànifé:",
+ "newpages-username": "Ahàǹjìème:",
"ancientpages": "Ihü díkárí íchié",
- "move": "Páfụ",
- "movethispage": "Páfù ihüá",
+ "move": "Papụ̀",
+ "movethispage": "Papụ̀ ihuâ",
"notargettitle": "Ntido adighị",
"pager-newer-n": "{{PLURAL:$1|1 nke ohúrù|$1 nke ohúrù}}",
"pager-older-n": "{{PLURAL:$1|1 nke ichié |$1 nke ichié}}",
"apisandbox-results": "Nfụ́fụ̀tà",
"booksources": "Ébé ákwúkwó shị",
"booksources-search-legend": "Tuó íshí akwúkwó shì",
+ "booksources-search": "Tùwe",
"specialloguserlabel": "Ọ'bànifé:",
"speciallogtitlelabel": "Ishi:",
"log": "Ndetu-nchétá",
"prevpage": "Ihü nke búzọr ($1)",
"allpagesfrom": "Zi ihü bídóró na:",
"allpagesto": "Zi na ihu ihü ná kwúshí nà:",
- "allarticles": "Ihü níle",
+ "allarticles": "Ihu níle",
"allinnamespace": "Ihü níle (ámááhạ $1)",
"allpagessubmit": "Gá",
- "categories": "Ébéanọr",
+ "categories": "Ụdàkọ",
"sp-deletedcontributions-contribs": "ihe rürü di mkpa",
"linksearch": "Òtú jikodo di èzí",
- "linksearch-ns": "Áhàámá:",
- "linksearch-ok": "Chọwa",
+ "linksearch-ns": "Ahàm̀bara:",
+ "linksearch-ok": "Tùwe",
"linksearch-line": "$1 jikọdọ shí $2",
"listusers-submit": "Zi",
- "listusers-noresult": "Ọ hügị ọ'bànifé.",
+ "listusers-noresult": "À chọfụ̀tàhụ̀ghị̀ òjìème.",
"listusers-blocked": "(kwàchịrị)",
- "activeusers-noresult": "Ọ hügị ọ'bànifé.",
+ "activeusers-noresult": "À chọfụ̀tàhụ̀ghị̀ òjìème.",
"listgrouprights-group": "Ọtú",
"listgrouprights-rights": "Nkwènyé",
"listgrouprights-members": "(ndetu ndi nọr nga)",
"listgrouprights-addgroup": "Gbàkọ {{PLURAL:$2|ọtú|ọtú}}: $1",
"listgrouprights-addgroup-all": "Tìnyé ọtú nílé",
+ "listgrouprights-namespaceprotection-namespace": "Ahàm̀bara",
"emailuser": "Zi onye á ózí-nsónùsòrò",
"defemailsubject": "e-mail {{SITENAME}}",
+ "emailusername": "Ahàǹjìème:",
+ "emailusernamesubmit": "Zibànye",
"emailfrom": "Onye banyere ya:",
"emailto": "Onye o gi ru:",
"emailsubject": "Gbàsịrị:",
"emailmessage": "Ozi:",
"emailsend": "Zí ozi",
"emailsent": "E-mail zìrì",
- "watchlist": "Ndetu ihem ne lé",
- "mywatchlist": "Ndetu ihem ne lé",
+ "watchlist": "Ùlìle",
+ "mywatchlist": "Ùlìlem",
"watchlistfor2": "Maka $1 $2",
"addedwatchtext": "Ihü \"[[:$1]]\" à bányéré [[Special:Watchlist|ndétu ihe Í ne lé]].\nIhe gi gbanwe na ógè gi bya nà ihüá na ihü okwu ya gi di ndétu ngáhù, na ihü gi da na mkpụrụ édé '''sírí íke''' ímé [[Special:RecentChanges|ndétu gbanwere méré na ogè nso]] ka ȯ dí òfelè Í hü ya.",
"removedwatchtext": "Ihü \"[[:$1]]\" à fwüó lá [[Special:Watchlist|ihe ndétu ihe Í ne lé]].",
"watchlist-options": "Nrọta ndetu nlènlé",
"watching": "O na hü...",
"unwatching": "O mele ka o na á hü kwagi...",
- "enotif_impersonal_salutation": "ọ'bànifé {{SITENAME}}",
+ "enotif_impersonal_salutation": "Òjìème {{SITENAME}}",
"enotif_anon_editor": "ọ'bànifé ézíghị ihu $1",
"created": "kèrè",
"changed": "gbanwere",
"maximum-size": "Ívù nke ukwu:",
"pagesize": "(byte)",
"restriction-edit": "Mèzi",
- "restriction-move": "Páfụ",
+ "restriction-move": "Papụ̀",
"restriction-create": "Ké",
"restriction-upload": "Tinyénélú",
"restriction-level-all": "ọtú nke ȯbulà",
"undeletelink": "lé/dosimá",
"undeleteviewlink": "lé",
"undeletecomment": "Mgbághapụtà:",
- "undelete-search-submit": "Chọwa",
+ "undelete-search-submit": "Tùwe",
"undelete-show-file-submit": "Eeh",
- "namespace": "Áhàámá:",
- "invert": "kwùtúárí ihe áká nọr",
+ "namespace": "Ahàm̀bara:",
+ "invert": "Tụgha ǹke ǹhọ̀rọ",
"blanknamespace": "(Ḿkpà)",
"contributions": "Ihe ọ'bànifé rürü",
"contributions-title": "Orü ọ'bànifé nà $1",
"mycontris": "Ihem mẹtụrụ na orürü",
"contribsub2": "Maka $1 ($2)",
- "uctop": "(ishi)",
+ "uctop": "(dị ùgbu â)",
"month": "Shi önwa (na nke ndi mbu):",
"year": "Shi afọr (na ndi nke mbu):",
"sp-contributions-newbies": "Zí orü áká ọ'bànifé ohúru náni",
"sp-contributions-deleted": "orü ọ'bànifé gbakashịrị",
"sp-contributions-uploads": "tinyere na élu.",
"sp-contributions-logs": "ndetu-nchétá",
- "sp-contributions-talk": "okwu",
+ "sp-contributions-talk": "nkàta",
"sp-contributions-search": "Tuó ihe há rürü",
"sp-contributions-username": "IP mà ọ bu áhà ọ'bànifé:",
- "sp-contributions-submit": "Chọwa",
+ "sp-contributions-submit": "Tùwe",
"whatlinkshere": "Ihe na bia nga",
"whatlinkshere-title": "Ihü ná gá \"$1\" shí jikodo",
"whatlinkshere-page": "Ihü:",
"isimage": "jikodo nnunuuche",
"whatlinkshere-prev": "{{PLURAL:$1|nke dí nà àzú|$1 nke dí nà àzú}}",
"whatlinkshere-next": "{{PLURAL:$1|nke sọrọ|$1 nke sọrọ}}",
- "whatlinkshere-links": " jikodo",
+ "whatlinkshere-links": "← òjikọ",
"whatlinkshere-hideredirs": "$1 nke kufùrù",
"whatlinkshere-hidetrans": "$1 ọ jè ákwúkwó usòrò",
"whatlinkshere-hidelinks": "Jikodo $1",
"ipb-unblock": "Ákwàchịrị áhà ọ'bànifé ma IP",
"unblockip": "Ákwàchịrị ọ'bànifé",
"unblocked": "há kwàchịrị [[User:$1|$1]]",
+ "autoblocklist-submit": "Tùwe",
"ipblocklist": "Ọ'bànifé kwáchírí",
"blocklist-target": "Ẹ́té",
"blocklist-expiry": "Gbá ọ́kà",
- "ipblocklist-submit": "Chọwa",
+ "ipblocklist-submit": "Tùwe",
"infiniteblock": "ébìébì ùdìdì",
"anononlyblock": "anon. náni",
"emailblock": "ha kwàchịrị e-mail",
"blocklink": "mèché",
"unblocklink": "a kwadokwàlà",
"change-blocklink": "gbanwe ngwùgwù",
- "contribslink": "orürü",
+ "contribslink": "ọrụrụ",
"blocklogpage": "Ndetù échìchè nke mbàchì",
"blocklogentry": "kwụchi [[$1]] jí ógè ne $2 $3",
"unblocklogentry": "àkwáchị gị $1",
"block-log-flags-noemail": "ha kwàchịrị e-mail",
"lockdb": "Gbàchí uche nsónùsòrò",
"unlockbtn": "Ágbàchịkwàlà uche nsónùsòrò",
- "move-page": "Páfụ $1",
+ "move-page": "Papụ̀ $1",
"move-page-legend": "Páfù ihü",
"movepagetext": "Í jí ákwúkwó òchá nke di na àlà gi gȯwá ótù ihü áhà ozor, na ȯ gi kwáfu ákíkó mbu ya na áhà nke ohürù.\nÍshí ihü nke ichié gi bu zi nkúfù gi gá áhà ohürù nke áhụ.\nÍ nwèríkí kúwárí nkúfù nke na ga áhà nke mbu na áká ya.\nȮ bu na Í chȯgị, kpàchákwá ánya Í lé má màkà nkúfù na gbá [[Special:DoubleRedirects|abụọ]] ma [[Special:BrokenRedirects|nkúfù gbájírí]].\nȮ dị na áká gi Í kpáchá ánya na jikodo na gá ébé o kwèshírí ga.\n\nChètákwá na ihü nke áhù '''ágághị''' a pú ȯ bu na ȯ dị ihü nwéré áhà áhù, bèelụ mà ȯ díghị ihe nọr ya na ímé ma ȯ bu nkúfù na onwé ya nke enweghị orürü nke mbu.\nIhe á fùtàrà na Í nwèríkí gọwáríá áhà ihü na nke mbu ya ȯ bu na Í gọrọ ọghọm, na Ì nwéghíkí dé na élú ihü di kwa.\n\n'''Kpàchákwá Ntị!'''\nIhe á nwèríkí bu ngbanwe ukwu mákà ihü ne wu;\nBiko kpàchá kwa ánya Í mà na ihe í ne mé na ógè gbárá mbu mgbè Í gí mé ya.",
"movepagetalktext": "Ihü owu ya gi fwüor na áká ya na ihü nke gárá '''bèelụ mà:'''\n*Ihü okwu nke énwéghị ihe nọr na ímé ya na ȯ dị nà áhà ohürù nke áhù, mà\n*Í piáfù igbé nọr nà àlà ngá.\n\nNa nke, Í gi páfù na Í mékȯtá ihü nà onwé gi ọ bu nà Í chọrọ.",
"newtitle": "Gá íshí édémédé nke:",
"move-watch": "Lèmá ihü ó shị na ihü ȯ na gá",
- "movepagebtn": "Páfù ihü",
+ "movepagebtn": "Papụ̀ ihuâ",
"pagemovedsub": "Mpúzié ẹ meelá",
"movepage-moved": "'''\"$1\" páfùrù Í gá \"$2\"'''",
"articleexists": " Ihü ótù nwèkwàrà áhà nke áhù, mà áhà Í chọrọ à búghị ézíboté.\nBiko wèré áhà ozor.",
"move-talk-subpages": "Páfù ihü-n-ímé nke ihü okwu (nè rú $1)",
"movepage-page-moved": "Ihü $1 a páfùrù gá $2.",
"movepage-page-unmoved": "Ihü $1 énweghịkị páfù gá $2.",
- "movelogpage": "Páfù ntínyé",
+ "movelogpage": "Papụ̀ ndenye",
"movereason": "Mgbághapụtà:",
"revertmove": "gbanwe lá àzú",
"delete_and_move_text": "== I kachafu gi me ==\nEbe ihü gé rú \"[[:$1]]\" di kwa.\nI chorí kàchafu ya ka uzor mepo maka mpuzie ne me?",
"importlogpage": "Hubàtà ndetu",
"tooltip-pt-userpage": "Ihü ọ'bànifé gi",
"tooltip-pt-mytalk": "Ihü akíkó gi",
- "tooltip-pt-preferences": "Otú Í shị na dose ihe gi",
+ "tooltip-pt-preferences": "Ndoziri {{GENDER:|gị}}",
"tooltip-pt-watchlist": "Ndetu ihü Í ne lé màkà ihe gị gbanwe",
"tooltip-pt-mycontris": "Ndetù ihe Í rürü",
"tooltip-pt-login": "Anyi si ka Í gbanyé; chetákwá na nsogbu adighi I gbanye ma Í chógị gbànyé",
"tooltip-pt-logout": "Fwuör",
"tooltip-ca-talk": "Akíkó maka ihe di na ihü nka",
- "tooltip-ca-edit": "Í nwẹríkí rü na ihü nka. Biko jí mkpátá nlélé mgbe Í na domá ihüá",
+ "tooltip-ca-edit": "Mèzi ihuâ",
"tooltip-ca-addsection": "Binyíte nkeji ohúrù",
- "tooltip-ca-viewsource": "Ihü nke cẹdolu.\nÍ nwèríkí lé mkpụrụ ya",
+ "tooltip-ca-viewsource": "Ihu â dị̀ ǹchèdò.\nỊ nwẹ̀rẹ̀ ike ị hụ mkpụrụ ya",
"tooltip-ca-history": "Orü ichié na ihüá",
"tooltip-ca-protect": "Cẹdolu ihüá",
"tooltip-ca-unprotect": "Gbánwe ncẹdo ihüá",
"tooltip-ca-delete": "Bakashia ihüá",
- "tooltip-ca-move": "Puzie ihüá",
+ "tooltip-ca-move": "Papụ̀ ihuâ",
"tooltip-ca-watch": "Tìnyé ihü á na ndétu ihe Í ne lé",
"tooltip-ca-unwatch": "Kwáfụ ihüá shí ndetu ihe m ne lé",
- "tooltip-search": "Chọwa {{SITENAME}}",
+ "tooltip-search": "Tu nà {{SITENAME}}",
"tooltip-search-go": "Gá na ihü nwere kwa áhà nke ma o di",
"tooltip-search-fulltext": "Chọwa na ihü maka mpkurụ okwu á",
- "tooltip-p-logo": "Ga na ihü mbu",
- "tooltip-n-mainpage": "Ga na ihü mbu",
+ "tooltip-p-logo": "Ga nà ihu m̀bụ",
+ "tooltip-n-mainpage": "Jèe ihu m̀bụ",
"tooltip-n-mainpage-description": "Ga na ihü mbu",
"tooltip-n-portal": "Maka orürü, gi ka Í nweríkí mé, ébé ha na tú ihe",
"tooltip-n-currentevents": "Tuó ákíkó mbu màkà ihe ne me ubwá",
"file-info-gif-looped": "etemte",
"newimages-legend": "Nzàtà",
"noimages": "Ọ díghì ihe di ngá Í lé.",
- "ilsubmit": "Chọwa",
+ "ilsubmit": "Tùwe",
"bydate": "shi afọ",
"just-now": "ùgbú ùgbúa",
"bad_image_list": "Ọtụ ȯ dị détùrù ngá:\n\nNání ndétu ihe (áhirí jí * bídó) dị na ihe ȯ chọrọ.\nJikodo bu nke mbu na áhìrì gí jikodo ya nà ȧkwúkwó orünotu di njö.\nJikodo nke gị byá àzú na áhìrì nke òfu á bu nke nwéríkí gáfè, díkà ihü ébé ȧkwúkwó orünotu áhu di ímé áhìrì ya.",
"exif-imagelength": "Ógólógó",
"exif-orientation": "Ívú nà àsáa",
"exif-imagedescription": "Íshí nhuunuche",
+ "exif-software": "Ndiriusòrò ejìème",
"exif-artist": "Odé ákwụ́kwọ́",
"exif-exifversion": "Ùdị Exif",
"exif-colorspace": "Ámá àgwà",
"exif-citydest": "Ámá ukwu ziri",
"exif-writer": "Òdìdè",
"exif-languagecode": "Ásụ̀sụ̀",
- "exif-iimcategory": "Ébéonọr",
+ "exif-iimcategory": "Ụdàkọ",
"exif-label": "Ọdụ",
"exif-orientation-1": "Nkịtị",
"exif-exposureprogram-1": "Ònyèmáká",
"exif-urgency-normal": "Nkịtị ($1)",
"exif-urgency-low": "Nàlà ($1)",
"exif-urgency-high": "Nélú ($1)",
- "namespacesall": "nke níle",
+ "namespacesall": "ha níle",
"monthsall": "nke níle",
"recreate": "Ké ya ohúrù",
"confirm_purge_button": "Ngwanu",
"version-entrypoints-header-entrypoint": "Ébé ọ̀bụ̀bà",
"version-entrypoints-header-url": "URL",
"fileduplicatesearch-filename": "Áhà usòrò:",
- "fileduplicatesearch-submit": "Chọwa",
+ "fileduplicatesearch-submit": "Tùwe",
"specialpages": "Ihü mkpà",
"specialpages-group-other": "Ihü mkpà nke ozor",
"specialpages-group-login": "Banyé / ké buwa",
"diff-form": "'''àhú'''",
"dberr-problems": "Ndó! Ámá nka nwere nsogbu ime ime.",
"htmlform-required": "Ọgụgụ nke gi dị",
- "htmlform-submit": "Dànyé",
+ "htmlform-submit": "Zibànye",
"htmlform-reset": "Emekwàlà gbanwere",
"htmlform-selectorother-other": "Nke ozor",
+ "restore-count-files": "{{PLURAL:$1|1 àfabà |àfabà $1}}",
"revdelete-content-hid": "ihe zọ̀nàri",
"rightsnone": "(efù)",
+ "feedback-cancel": "Hapụ̀",
"feedback-close": "Ọméchá.",
"feedback-message": "Ozi:",
- "searchsuggest-search": "Chọwa",
+ "feedback-submit": "Zibànye",
+ "searchsuggest-search": "Tu nà {{SITENAME}}",
"expand_templates_ok": "Ngwanu",
+ "pagelang-submit": "Zibànye",
"special-characters-group-latin": "Latin",
- "special-characters-group-latinextended": "Latin dọrọ",
+ "special-characters-group-latinextended": "Latin dọsàrà",
"special-characters-group-ipa": "IPA",
"special-characters-group-symbols": "Nkárí",
"special-characters-group-greek": "Greek",
"Tusholi"
]
},
- "tog-underline": "ТIатовжама кIала така хьакхар:",
- "tog-hideminor": "Къайладаккха зӏамига дола хувцамаш керда хувцамашта юкъера",
- "tog-hidepatrolled": "Къайладаккха ха дера чакхдаьнна дола (патрулированные) хувцамаш керда хувцамашта юкъера",
- "tog-newpageshidepatrolled": "Ð\9aÑ\8aайлаÑ\8fÑ\8cккÑ\85а Ñ\85а деÑ\80а Ñ\87акÑ\85Ñ\8aÑ\8fнна йола (паÑ\82Ñ\80Ñ\83лиÑ\80ованные) оагIонаш керда оагIонашта юкъера",
- "tog-hidecategorization": "Ð\9aÑ\8aайлаÑ\8fÑ\85а оагÓ\80онай каÑ\82егоÑ\80еш",
- "tog-extendwatchlist": "Хьашеръяь йола зем бара список, массадола хувцамаш ше чулоацаш, тIеххьара даь хувцамаш хинна ца Iеш.",
- "tog-usenewrc": "Ð¥Ñ\83вÑ\86амаÑ\88 Ñ\82оабаÑ\88 еÑ\88 леладе кеÑ\80да нийÑ\81даÑ\80аÑ\88ка а, зем баÑ\80а Ñ\81пиÑ\81ка чу а",
- "tog-numberheadings": "Ð\90вÑ\82омаÑ\82иÑ\87еÑ\81ки нÑ\83меÑ\80аÑ\86и Ñ\85Ñ\8cае доакÑ\8aой Ñ\86IеÑ\80ашта",
- "tog-showtoolbar": "Ð\93IиÑ\80Ñ\81ий панелÑ\8c Ñ\85Ñ\8cаÑ\85Ñ\8cокÑ\85а Ñ\85Ñ\83вÑ\86ам беÑ\87 хана",
+ "tog-underline": "ТIатовжамá кIала така хьакхар:",
+ "tog-hideminor": "Къайладаха зӏамагIа хувцамаш керда хувцамашта юкъера",
+ "tog-hidepatrolled": "Къайладаха техка чакхдаьнна дола (патрулированные, проверенные) хувцамаш керда хувцамашта юкъера",
+ "tog-newpageshidepatrolled": "Ð\9aÑ\8aайлаÑ\8fÑ\85а Ñ\82еÑ\85ка Ñ\87акÑ\85Ñ\8aÑ\8fнна йола (паÑ\82Ñ\80Ñ\83лиÑ\80ованнÑ\8bе, пÑ\80овеÑ\80енные) оагIонаш керда оагIонашта юкъера",
+ "tog-hidecategorization": "Ð\9aÑ\8aайлаÑ\8fÑ\85а оагÓ\80оний оагÓ\80аÑ\82аш",
+ "tog-extendwatchlist": "Хьашеръе зéма хьаязъяьр шедола хувцамаш юкъелоацаш, тIехьара даь хувцамаш хинна ца Iеш.",
+ "tog-usenewrc": "Ð¥Ñ\83вÑ\86амеÑ\85 Ñ\82оабаÑ\88 е кеÑ\80да нийÑ\81даÑ\80аÑ\88ка а зéма Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80а чу а",
+ "tog-numberheadings": "Ше-Ñ\88егIа номеÑ\80аÑ\88 Ñ\83вÑ\82Ñ\82ае кепакеÑ\80Ñ\82ошта",
+ "tog-showtoolbar": "Ð\9aеÑ\87ала панелÑ\8c Ñ\85Ñ\8cаÑ\85Ñ\8cокÑ\85а Ñ\85Ñ\83вÑ\86ам беÑ\87а хана",
"tog-editondblclick": "Нисъе оагӀонаш шозза IотӀатоӀаеча (JavaScript)",
"tog-editsectiononrightclick": "Нийсде дáкъа шозза дахка аьттехьара тоIаер тӀатоӀайича дáкъа цIера тIа (JavaScript)",
"tog-watchcreations": "Зем беш йола оагIонашта а файлашта а тIатоха аз хьаяь оагIонаши чуяьккха файлаши",
"tog-watchdeletion": "Зем беш йола оагIонашта а файлашта а тIатоха аз дIаяьккха оагIонаши файлаши",
"tog-minordefault": "Массаза зIамига долаш санна белгалде хувцамаш.",
"tog-previewontop": "Хьалххе бӀаргтохар хьагойта хувцама кора хьалхашкахь",
- "tog-previewonfirst": "Хувцам бе дехьаваьлча хьалххе бӀаргтохар хьахьокха",
+ "tog-previewonfirst": "Ð¥Ñ\83вÑ\86ам бе аÑ\8cнна деÑ\85Ñ\8cаваÑ\8cлÑ\87а Ñ\85Ñ\8cалÑ\85Ñ\85е бÓ\80аÑ\80гÑ\82оÑ\85аÑ\80 Ñ\85Ñ\8cаÑ\85Ñ\8cокÑ\85а",
"tog-enotifwatchlistpages": "Электронни почте гIолла хоам бе сога нагахь аз зем беш йола оагIонаши файлаши цхьанне хийцача",
"tog-enotifusertalkpages": "Электронни почте гIолла хоам бе сога са дувца оттадара оагIув хийцача",
"tog-enotifminoredits": "ОагIонаштеи файлаштеи даь хинна хувцамаш геттара зIамига дале а хоам бе сога",
"tog-enotifrevealaddr": "ДӀабӀаргадайта са поштан цӀай нахá дӀатӀаухача цхьа хӀама хайташ долча хоамаш чу",
- "tog-shownumberswatching": "Ер оагIув шоаш зембеча оагIонашта юкъеяьккхача доакьошхой таьрахь гойта",
+ "tog-shownumberswatching": "Ер оагIув шоаш зембеча оагIонашта юкъеяьккха болча доакьошхой таьрахь хьагойта",
"tog-oldsig": "Хьа карара кулг яздар:",
"tog-fancysig": "Кулг яздара ший йола вики-разметка (автоматически тIахьожаярг йоацаш)",
- "tog-uselivepreview": "Хьахьокха хьалххе бӀаргтохар оагӀув юха хьа ца елаш",
+ "tog-uselivepreview": "Хьахьокха хьалххе бӀаргтохар оагӀув юха хьа а ца елаш",
"tog-forceeditsummary": "ДIахьалхадаккха, нагахьа санна хувцама йоазонца сурт оттадара моттиг хьалъйизанза яле",
"tog-watchlisthideown": "Са зем бара хьаязъяьр чура хувцамаш къайладаха",
"tog-watchlisthidebots": "Зем бара хьаязъяьр чура ботий хувцамаш къайладаха",
"tog-useeditwarning": "Хоамбе хьадаь хувцамаш дӀа а ца яздеш аз болх дӀаберзабеча хана",
"underline-always": "Даиман",
"underline-never": "ЦIаккха",
- "underline-default": "Ð\91Ñ\80аÑ\83зеÑ\80а гIиÑ\80Ñ\81аÑ\88 Ñ\82оаÑ\8fÑ\80аÑ\88 лелае",
- "editfont-style": "Хувцама моттиге шрифта тайпа:",
+ "underline-default": "Ð\91Ñ\80аÑ\83зеÑ\80а оÑ\82Ñ\82амаÑ\88 леладе",
+ "editfont-style": "Хувцам беча моттигера шрифта тайпа:",
"editfont-monospace": "Цхьатарра йоаца шрифт",
"editfont-sansserif": "Белгало йоаца шрифт",
"editfont-serif": "Белгало йола шрифт",
"category-media-header": "\"$1\" яхача оагIата чура файлаш",
"category-empty": "''Ер оагIат хӀанза яьсса я (цхьаккха оагIонаш е файлаш йоацаш).''",
"hidden-categories": "{{PLURAL:$1|1=Къайла оагIат|Къайла оагIаташ}}",
- "hidden-category-category": "Ð\9aÑ\8aайла каÑ\82егоÑ\80еш",
+ "hidden-category-category": "Ð\9aÑ\8aайла оагÓ\80аÑ\82аш",
"category-subcat-count": "{{PLURAL:$2|Укх оагIата чу я алхха ер кIалоагIат.|Укх оагIата чу гуш я $2-нен юкъера $1 {{PLURAL:$1|кIалоагIат}} }}",
"category-subcat-count-limited": "Укх категори чу {{PLURAL:$1|кIалхара категори|$1 кIалхара категореш}} я.",
"category-article-count": "{{PLURAL:$2|Укх оагIата чу цаI мара оагIув яц.|Укх оагIата чу я $2 оагӀув, царех оагӀонгахьа {{PLURAL:$1|хьагойт $1 оагӀув}}}}",
- "category-article-count-limited": "УкÑ\85 каÑ\82егоÑ\80и Ñ\87Ñ\83 {{PLURAL:$1|$1 оагÓ\80Ñ\83в Ñ\8f|1=Ñ\86аI оагӀув мара яц}}.",
+ "category-article-count-limited": "УкÑ\85 оагÓ\80аÑ\82а Ñ\87Ñ\83 {{PLURAL:$1|$1 оагÓ\80Ñ\83в Ñ\8f|1=Ñ\86Ñ\85Ñ\8cа оагӀув мара яц}}.",
"category-file-count": "{{PLURAL:$2|Укх оагIата чу цаI мара файл яц.|Укх оагIата чу долча $2 файлах {{PLURAL:$1|1=хьагойт $1 файл}} }}",
"category-file-count-limited": "Укх категори чу {{PLURAL:$1|$1 файл|$1 файлаш|1=цаI мара файл яц}}.",
"listingcontinuesabbrev": "(дIахо)",
"anontalk": "Дувца оттадар",
"navigation": "Навигаци",
"and": " а",
- "faq": "Ð\9aÐ\9bÐ¥",
+ "faq": "Ð\9aаÑ\81Ñ\82-каÑ\81Ñ\82Ñ\82а Ñ\82елаÑ\88 дола Ñ\85аÑ\82Ñ\82аÑ\80аÑ\88",
"actions": "Ардамаш",
"namespaces": "ЦIерий аренаш",
"variants": "Эршаш",
"tagline": "Кечал я укхазара: {{grammar:genitive|{{SITENAME}}}}",
"help": "Новкъoстал",
"search": "Лахаp",
- "searchbutton": "Хьалáха",
+ "searchbutton": "Хьалаха",
"go": "Дехьавала",
"searcharticle": "Дехьавала",
"history": "Истори",
"history_short": "Истори",
- "updatedmarker": "Со Ñ\82IеÑ\85Ñ\85Ñ\8cаÑ\80а Ñ\83кÑ\85аз Ñ\85иннаÑ\87Ñ\83л Ñ\82IеÑ\85Ñ\8cагIа кеÑ\80дадаÑ\8cккÑ\85ад",
+ "updatedmarker": "кеÑ\80дадаÑ\8cккÑ\85ад Ñ\81о Ñ\82IеÑ\85Ñ\85Ñ\8cаÑ\80а Ñ\83кÑ\85аза Ñ\85иннаÑ\87Ñ\83л Ñ\82IеÑ\85Ñ\8cагIа",
"printableversion": "Зарба тохара эрш",
"permalink": "Массаза болх бу тӏатовжам",
"print": "Зарба тоха",
"categorypage": "Категорен оагIон бIаргтоха",
"viewtalkpage": "Дувца оттадара бIаргтоха",
"otherlanguages": "Кхыча меттаех",
- "redirectedfrom": "($1 дIа-сахьожаяьй укхаз)",
- "redirectpagesub": "Ð\9eагIÑ\83в-дIа-Ñ\81аÑ\85Ñ\8cожадаÑ\80",
+ "redirectedfrom": "($1 яха оагIув дIа-хьа хьожаяьй укхаза)",
+ "redirectpagesub": "Ð\94Iа-Ñ\85Ñ\8cа Ñ\85Ñ\8cожаваÑ\80а оагIÑ\83в",
"redirectto": "ДIа-хьа хьожавар укхаза:",
"lastmodifiedat": "Ер оагӀув тӀеххьара хийца хиннай укх ха́на: $1, $2.",
"viewcount": "Укх оагIонга хьежа хиннаб $1{{PLURAL:$1|-зза}}.",
"pool-queuefull": "ДIахаттарий гулдер хьалдизад",
"pool-errorunknown": "Довзаш доаца гӀалат",
"poolcounter-usage-error": "Пайда эцара гIалат: $1",
- "aboutsite": "{{grammar:genitive|{{SITENAME}}}} лаьца дар",
+ "aboutsite": "Википедех лаьца",
"aboutpage": "Project:Сурт оттадар",
"copyright": "Чулоацамá тIакхоачилга да $1 яхача лицензе бокъоношца, нагахь санна кхыдар белгалдаь деце.",
"copyrightpage": "{{ns:project}}:Автора бокъонаш",
"policy-url": "Project:Бокъонаш",
"portal": "Юкъара ков",
"portal-url": "Project:Юкъара ков",
- "privacy": "КъайлагIара хIамай политика",
+ "privacy": "КъайлагIарча хIамай политика",
"privacypage": "Project:КъайлагIара хIамай политика",
"badaccess": "ТIакхоачилга гӀалат",
"badaccess-group0": "Оаш дIадийха хинна ардам кхоачашде йиш яц шун.",
"versionrequiredtext": "Укх оагIонца болх бергболаш $1 версех йола MediaWiki эша. Хьажа [[Special:Version|програмни Iалашдарах бола хоамага]].",
"ok": "Мег",
"retrievedfrom": "Хьаст — «$1»",
- "youhavenewmessages": "{{PLURAL:$3|Хьога денад}} $1 ($2).",
+ "youhavenewmessages": "{{PLURAL:$3|Хьога}} $1 бéнаб ($2).",
"youhavenewmessagesfromusers": "{{PLURAL:$4|Хьога кхаьчад}} $1 {{PLURAL:$3|1=$3 доакъашхочунгара|$3 доакъашхоштагара|1=кхыволча доакъашхочунгара}} ($2).",
- "newmessageslinkplural": "{{PLURAL:$1|керда хоам|999=керда хоамаш}}",
+ "newmessageslinkplural": "{{PLURAL:$1|керда хоам}}",
"newmessagesdifflinkplural": "{{PLURAL:$1|тӀехьара хувцам|999=тӀехьара хувцамаш}}",
"youhavenewmessagesmulti": "Хьога кхаьчад керда хоамаш $1 чу",
"editsection": "нийсде",
"databaseerror-function": "Функци: $1",
"databaseerror-error": "ГIалат: $1",
"missing-article": "Дарий гуллам чу дIайийха текст яц укх оагIон «$1» чура $2 корадар дезаш хинна.\n\nИз мо гIалат нийсалуш хул тишъенна тIахьожаярга гIолла дIадаьккха оагӀон хувцама истори тӀа дехьавала гӀертача.\n\nНагахьа санна из иштта децe, шоана программни Ӏалашдар чу гIалат кораяь хила мега.\nДехар да, цу гIулакха хоам бе цхьа [[Special:ListUsers/sysop|мазаурхалдерчунга]], укхазар URL белгаляьккха.",
- "missingarticle-rev": "(верси № $1)",
+ "missingarticle-rev": "(эрш № $1)",
"missingarticle-diff": "(башхало: $1, $2)",
"internalerror": "Чура гӀалат",
"internalerror_info": "Чура гӀалат: $1",
"welcomeuser": "Маьрша воагIалва, доакъашхо $1!",
"yourname": "Дагара йоазон цIи:",
"userlogin-yourname": "Доакъашхочун цӀи",
- "userlogin-yourname-ph": "Iочуязъе хьай учёта яздара (доакъашхочун) цӀи",
+ "userlogin-yourname-ph": "Iочуязъе хьай дагара йоазон цӀи",
"createacct-another-username-ph": "Iочуязъе доакъашхочун цӀи",
- "yourpassword": "Ð\9aÑ\8aайладIоагIа:",
+ "yourpassword": "Ð\9fаÑ\80олÑ\8c:",
"userlogin-yourpassword": "Пароль",
"userlogin-yourpassword-ph": "Ӏочуязъе хьай пароль",
"createacct-yourpassword-ph": "Ӏочуязъе пароль",
- "yourpasswordagain": "ЮÑ\85аÑ\8fзде кÑ\8aайладIоагIа:",
+ "yourpasswordagain": "Ð\9aÑ\85Ñ\8b Ñ\86Ñ\85Ñ\8cаÑ\8cкÑ\85аза паÑ\80олÑ\8c Ñ\8fзÑ\8aÑ\8fÑ\80:",
"createacct-yourpasswordagain": "Бакъйе пароль",
"createacct-yourpasswordagain-ph": "Кхы цхьаькхаза Ӏочуязъе пароль",
"userlogin-remembermypassword": "Ражача чувиса",
"headline_tip": "2-гӀа лагӀара дáкъа цIи",
"nowiki_sample": "Укхаза хувца езаш йоаца текст хьачуоттае",
"nowiki_tip": "Теркал ма е вики-форматировани",
- "image_tip": "Чуоттаяь файл",
+ "image_tip": "Чухьнахьара файл",
"media_tip": "Файлá тIатовжам",
"sig_tip": "Хьа кулгаяздар а, хӀанзара ха а",
"hr_tip": "ПхьорагIен така (цох пайда эцар тIехдаьнна кастта ма де)",
"summary": "Хувцамий сурт оттадар",
"subject": "Тема/даькъа цIи:",
"minoredit": "ЗӀамига хувцам",
- "watchthis": "Зем бе укх оагӀон",
+ "watchthis": "Зем бе укх оагӀонна",
"savearticle": "ОагӀув дIаязъе",
"preview": "Хьалххе бIаргтохар",
"showpreview": "Хьалххе бIаргтохар",
"accmailtitle": "КъайладIоагӀа дӀадахьийтад",
"newarticle": "(Kерда)",
"newarticletext": "Шо тIатовжама гIолла дехьадаьннад йолаш йоацача оагӀон тӀа.\nИз хьакхолларгьйолаш кӀалхагӀа доалача корачу текст Iочуязъе (нагахьа санна кхетаде хала дале [$1 новкъосталара оагӀонга] хьажа).\nЦаховш укхаза нийсденнадале, шоай браузера чу '''Юха''' (Назад) яха тоIаера тӀа пӀелг тоӀабе.",
- "anontalkpagetext": "----\n<em>Ð\95Ñ\80 вовзаÑ\88 воаÑ\86аÑ\87а (Ñ\88ий дагаÑ\80а йоазÑ\83в кÑ\85Ñ\8b а Ñ\85Ñ\8cакÑ\85олланза) доакÑ\8aаÑ\88Ñ\85оÑ\87Ñ\83н дÑ\83вÑ\86а оÑ\82Ñ\82адаÑ\80а оагIÑ\83в Ñ\8f.</em>\nЦÑ\83 баÑ\85Ñ\8cане Ñ\82Ñ\85о декÑ\85аÑ\80ийла Ñ\86Ñ\83 Ñ\81ага иденÑ\82иÑ\84икаÑ\86и еÑ\80 дÑ\83Ñ\85Ñ\8cа Ñ\86Ñ\83н IP-Ñ\86Ó\80ай Ñ\85Ñ\8cаÑ\85Ñ\8cокÑ\85а.\nÐ\98з Ñ\86Ó\80ай леладеÑ\88 Ñ\85ила мег маÑ\81еÑ\85к кÑ\85Ñ\8bболÑ\87а доакÑ\8aаÑ\88Ñ\85ой а.\nÐ¥Ñ\8cо вовзаÑ\88 воаÑ\86а доакÑ\8aаÑ\88Ñ\85о вале,еÑ\80 Ñ\85оам Ñ\85Ñ\8cона боагIаÑ\88 баÑ\86 аÑ\8cнна Ñ\85еÑ\82аÑ\88 вале, дехар да [[Special:CreateAccount|хьакхолла дагара йоазув]] е [[Special:UserLogin|хьавовзийта ражá]], тIехьагIа хье тувлавайтаргвоацаш бовзаш боацача доакъашхошца.",
- "noarticletext": "ХIанза укх оагӀон тӀа текст яц.\nШун аьттув ба [[Special:Search/{{PAGENAME}}|цу тайпара цӀи хьоаяр лаха]] кхыйолча оагIонаш тIа, иштта\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} тептарий дIаяздаьраш лаха] е\n'''[{{fullurl:{{FULLPAGENAME}}|action=edit}} иззамо цӀи йолаш оагӀув хьакхолла]'''</span>.",
- "noarticletext-nopermission": "Ð¥Iанз Ñ\83кÑ\85 оагÓ\80он Ñ\82Ó\80а Ñ\82екÑ\81Ñ\82 Ñ\8fÑ\86.\nШÑ\83н аÑ\8cÑ\82Ñ\82Ñ\83в ба кÑ\85Ñ\8bйолÑ\87а оагIонаÑ\88 Ñ\82Iа [[Special:Search/{{PAGENAME}}|Ñ\86Ñ\83 Ñ\82айпаÑ\80а Ñ\86Ó\80и Ñ\85Ñ\8cоÑ\85аÑ\8fÑ\80 лаÑ\85а]], иÑ\88Ñ\82Ñ\82а <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} Ñ\82епÑ\82аÑ\80ай дIаяздаьраш лаха].</span> Ер оагӀув хьакхолла Хьа бокъо яц.",
+ "anontalkpagetext": "----\n<em>Ð\95Ñ\80 да вовзаÑ\88 воаÑ\86аÑ\87а (Ñ\88ий дагаÑ\80а йоазÑ\83в кÑ\85Ñ\8b а Ñ\85Ñ\8cакÑ\85олланза) доакÑ\8aаÑ\88Ñ\85оÑ\87Ñ\83н оагIÑ\83в Ñ\8eвÑ\86аÑ\80.</em>\nЦÑ\83 баÑ\85Ñ\8cане Ñ\82Ñ\85о декÑ\85аÑ\80ийла да Ñ\86Ñ\83 Ñ\81агá иденÑ\82иÑ\84икаÑ\86и еÑ\80 дÑ\83Ñ\85Ñ\8cа Ñ\86Ñ\83н IP-Ñ\86Ó\80ай Ñ\85Ñ\8cаÑ\85Ñ\8cокÑ\85а.\nÐ\98з Ñ\86Ó\80ай леладеÑ\88 Ñ\85ила мег маÑ\81еÑ\85к кÑ\85Ñ\8bболÑ\87а доакÑ\8aаÑ\88Ñ\85оÑ\88а а.\nÐ¥Ñ\8cо вовзаÑ\88 воаÑ\86а доакÑ\8aаÑ\88Ñ\85о вале, еÑ\80 Ñ\85оам Ñ\85Ñ\8cона боагIаÑ\88 баÑ\86 аÑ\8cнна Ñ\85еÑ\82аÑ\88 а вале, дехар да [[Special:CreateAccount|хьакхолла дагара йоазув]] е [[Special:UserLogin|хьавовзийта ражá]], тIехьагIа хье тувлавайтаргвоацаш бовзаш боацача доакъашхошца.",
+ "noarticletext": "ХIанз укх оагӀон тӀа текст яц.\nШун аьттув ба [[Special:Search/{{PAGENAME}}|цу тайпара цӀи хьоахаяр лаха]] кхыйолча оагIонаш тIа, иштта\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} тептарий дIаяздаьраш лаха] е\n'''[{{fullurl:{{FULLPAGENAME}}|action=edit}} иззамо цӀи йолаш оагӀув хьакхолла]'''</span>.",
+ "noarticletext-nopermission": "Ð¥Iанз Ñ\83кÑ\85 оагÓ\80он Ñ\82Ó\80а Ñ\82екÑ\81Ñ\82 Ñ\8fÑ\86.\nШÑ\83н аÑ\8cÑ\82Ñ\82Ñ\83в ба кÑ\85Ñ\8bйолÑ\87а оагIонаÑ\88 Ñ\82Iа [[Special:Search/{{PAGENAME}}|Ñ\86Ñ\83 Ñ\82айпаÑ\80а Ñ\86Ó\80и Ñ\85Ñ\8cоÑ\85аÑ\8fÑ\80 лаÑ\85а]], иÑ\88Ñ\82Ñ\82а <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} Ñ\82епÑ\82аÑ\80ий дIаяздаьраш лаха].</span> Ер оагӀув хьакхолла Хьа бокъо яц.",
"userpage-userdoesnotexist-view": "«$1» яха дагара йоазув долаш дац.",
"clearyourcache": "<strong>Теркал де.</strong> Хетаргахьа, оагIув дIаязъяь яьлча шоай браузера кэш IоцIанъе езаргья шун, даь хувцамаш гургдолаш.\n* <strong>Firefox / Safari:</strong> <em>Shift</em> яха лак тоIояь лоаттаеш инструментий цхьа дакъа тIа тоIае <em>Обновить</em> е <em>Ctrl-F5</em> тоIае е <em>Ctrl-R</em> (<em>⌘-R</em> Mac тIа)\n* <strong>Google Chrome:</strong> ТоIае <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> Mac тIа)\n* <strong>Internet Explorer:</strong> <em>Ctrl</em> яха лак тоIояь лоаттаеш, тоIае <em>Обновить</em> е <em>Ctrl-F5</em> тоIае\n* <strong>Opera:</strong> ДехьагIо <em>Menu → Настройки</em> (<em>Opera → Настройки</em> Mac тIа), тIаккха <em>Безопасность → Очистить историю посещений → Кэшированные изображения и файлы</em>",
"note": "'''Белгалдоахар:'''",
"yourtext": "Хьа текст",
"copyrightwarning": "Теркам бе, статьяй текста деррига хувцамаш а, тIатохараш а укх лицензи $2 хьалашца (условия) лоархIаш да (хь. $1).\nНагахь санна Шоай тексташ Шун пурам доацаш лоIаме даржийта а, моллагIа волча саго хувца йиш йолаш хилийта а Шун безам беце, уж укхаз (Википейде) ма язде.<br />\nИштта, Оаш бакъду Шоай тIатохама Шо автораш хилар, е из кеп яьккха укхаз хьачудаккхар лоIаме чудар долча хьаста (источник) тIара.\n'''АВТОРСКИ БОКЪОНАШЦА ЛОРАДЕШ ДОЛА МАТЕРИАЛАШ УКХАЗ ЧУ МА ДАХА!'''",
"templatesused": "Укх оагIон тIа {{PLURAL:$1|1=пайда эца ло|пайда эца лераш}}:",
- "templatesusedpreview": "БIаргтохара раже {{PLURAL:$1|1=пайда эцаш ло|пайда эцаш лераш}}:",
+ "templatesusedpreview": "БIаргтохар хьалотадича пайда эцаш {{PLURAL:$1|1=лелабеш бола ло|леладеш дола лераш}}:",
"template-protected": "(лорадаь да)",
"template-semiprotected": "(цхьа долча даькъе гIо оттадаь да)",
"hiddencategories": "Ер оагIув {{PLURAL:$1|$1 къайла категориех|1=цаI къайла категорех}} я:",
"undo-failure": "Ер нийсдар юхадаккха йиш яц юкъе даь хувцамаш бахьане",
"viewpagelogs": "Укх оагӀон тептараш хьахьокха",
"currentrev-asof": "ТӀехьара эрш $1",
- "revisionasof": "Ð\92еÑ\80Ñ\81и $1",
- "revision-info": "Ð\92еÑ\80Ñ\81и $1; {{GENDER:$6|$2}}$7",
- "previousrevision": "← Xьалхарча",
- "nextrevision": "ТIехьайоагIараш →",
+ "revisionasof": "ÐÑ\80Ñ\88 $1",
+ "revision-info": "ÐÑ\80Ñ\88 ($1); {{GENDER:$6|$2}}$7",
+ "previousrevision": "← XьалхайоагIа",
+ "nextrevision": "ТIехьайоагIа →",
"currentrevisionlink": "ХIанзара верси",
"cur": "хӀанза.",
"next": "тӀехь.",
"historyempty": "(яьсса)",
"history-feed-title": "Хувцамий истори",
"history-feed-description": "Укх оагӀон хувцамий истори вике чу",
- "history-feed-item-nocomment": "$1 → укх хана: $2",
+ "history-feed-item-nocomment": "$1 → укх хáна: $2",
"rev-delundel": "хьахьокха/къайлаяккха",
"rev-showdeleted": "хьахьокха",
"revdelete-show-file-submit": "XӀа-а",
"searchprofile-advanced": "Шердаь",
"searchprofile-articles-tooltip": "$1 чу лахар",
"searchprofile-images-tooltip": "Файлаш лахар",
- "searchprofile-everything-tooltip": "Массайола оагIонаш тIа лахар (дувцар оттадара оагIонаш чулоацаш)",
- "searchprofile-advanced-tooltip": "Iочуязаяь цIерий аренашка лаха",
+ "searchprofile-everything-tooltip": "Массайолча оагIонаш тIа лахар (дувцара оагIонаш чу а лоацаш)",
+ "searchprofile-advanced-tooltip": "Лаха хьахержача цIерий аренашка",
"search-result-size": "$1 ({{PLURAL:$2|$2 дош|$2 дешаш}})",
"search-result-category-size": "$1 {{PLURAL:$1|юкъедахар}} ($2 {{PLURAL:$2|кIалоагIат}}, $3 {{PLURAL:$3|файл}})",
- "search-redirect": "(дIа-хьахьожадар $1 тIара)",
+ "search-redirect": "($1 яхача оагIон тIара дIа-хьа хьожадар)",
"search-section": "(дáкъа «$1»)",
"search-file-match": "(цхьатара хул файла чударца)",
"search-suggest": "Хьона эшар ер хила мега: $1",
- "search-interwiki-caption": "Ð\93аÑ\80гаÑ\80Ñ\87а пÑ\80оекÑ\82еÑ\85 Ñ\85иннар",
+ "search-interwiki-caption": "Ð\9aÑ\85Ñ\8bйолÑ\87а гаÑ\80гаÑ\80Ñ\87а пÑ\80оекÑ\82аÑ\88ка коÑ\80адаÑ\8cр",
"search-interwiki-default": "Хьахиннараш укхазар $1:",
"search-interwiki-more": "(кхы а)",
"search-relatedarticle": "ВIашагIдувзаденна",
"powersearch-togglenone": "Цхьаккха",
"powersearch-remember": "Дагалáца хержар кхы тӀехьагӀа лохача хана накъадаргдолаш",
"preferences": "ГIирс тоаяраш",
- "mypreferences": "Ð\93IиÑ\80Ñ\81аш",
+ "mypreferences": "Ð\9eÑ\82Ñ\82амаш",
"prefs-skin": "ТIера кийчдара тема",
"skin-preview": "Хьалххе бIаргтохар",
"prefs-personal": "Доакъашхочун дараш",
"nchanges": "$1 {{PLURAL:$1|хувцам}}",
"enhancedrc-history": "истори",
"recentchanges": "Керда хувцамаш",
- "recentchanges-legend": "Ð\9aеÑ\80да Ñ\85Ñ\83вÑ\86амий гIиÑ\80Ñ\81аÑ\88 Ñ\82оаÑ\8fÑ\80аш",
+ "recentchanges-legend": "Ð\9aеÑ\80да Ñ\85Ñ\83вÑ\86амий оÑ\82Ñ\82амаш",
"recentchanges-summary": "КIалхагIа Iохьоахадаьд Википеден оагIонаш чу даь хувцамаш тIехьардараш лакхе долаш.",
"recentchanges-noresult": "Белгалъяьча хана цхьаккха хувцамаш даь хинна дац.",
"recentchanges-feed-description": "Хьéжа укх потоке вики чу тIехьара хувцамашка.",
"rc-change-size-new": "Хувцам баьнначул тӀехьагIа бола боарам: $1 {{PLURAL:$1|байт}}",
"rc-enhanced-expand": "Хьахьокха ма дарра",
"rc-enhanced-hide": "Къайладаккха ма дарра дар",
- "rc-old-title": "духхьара кхелла хиннай «$1» цӀи йолаш",
+ "rc-old-title": "юххьанцара кхелла хиннай «$1» цӀи йолаш",
"recentchangeslinked": "ВIашагIдувзаденна нийсдараш",
"recentchangeslinked-feed": "ВIашагIдувзаденна нийсдараш",
"recentchangeslinked-toolbox": "ВIашагIдувзаденна хувцамаш",
"license": "Лицензи ялар:",
"license-header": "Лицензировани",
"imgfile": "файл",
- "listfiles": "Файлай хьаязъяьр",
- "listfiles_date": "ТаÑ\8cÑ\80аÑ\85Ñ\8c",
+ "listfiles": "Файлий хьаязъяьр",
+ "listfiles_date": "Ð\94и",
"listfiles_name": "Файла цӀи",
"listfiles_user": "Доакъашхо",
"listfiles_size": "Боарам",
"listfiles_description": "Йоазонца сурт оттадар",
- "listfiles_count": "Ð\92еÑ\80Ñ\81и",
+ "listfiles_count": "ÐÑ\80Ñ\88",
"file-anchor-link": "Файл",
"filehist": "Файла истори",
- "filehist-help": "ТаÑ\8cÑ\80аÑ\85Ñ\8c/Ñ\85а Ñ\82Iа Ñ\82оIабе Ñ\86Ñ\83 Ñ\85ан Ñ\84айл миÑ\88Ñ\82а Ñ\85иннай Ñ\85Ñ\8cожаpгдолаш",
+ "filehist-help": "Ð\94и/Ñ\85а долÑ\87а IоÑ\82IаÑ\82оIае Ñ\86Ñ\83 Ñ\85ана Ñ\84айл миÑ\88Ñ\82а Ñ\85иннай Ñ\85Ñ\8cажа йиÑ\88 Ñ\85Ñ\83pгÑ\8cйолаш",
"filehist-revert": "юхаяьккха",
"filehist-current": "xIанзара",
- "filehist-datetime": "ТаÑ\8cÑ\80аÑ\85Ñ\8c/Ха",
+ "filehist-datetime": "Ð\94и/Ха",
"filehist-thumb": "ЗIамигасурт",
- "filehist-thumbtext": "Ð\97Iамига Ñ\81Ñ\83Ñ\80Ñ\82 Ñ\83кÑ\85 веÑ\80Ñ\81ин $1",
+ "filehist-thumbtext": "Ð\97IамагIа йола Ñ\8dÑ\80Ñ\88 Ñ\83кÑ\85 Ñ\85ана Ñ\85инна: $1",
"filehist-nothumb": "Миниатюра яц",
"filehist-user": "Доакъашхо",
"filehist-dimensions": "Файла боарам",
"filehist-comment": "Белгалдаккхар",
"imagelinks": "Файлах пайда эцар",
"linkstoimage": "{{PLURAL:$1|1=ТIехьайоагIача $1 оагIо тIахьожаву|ТIехьайоагIача $1 оагIонаш тIахьожаву}} укх файла тIа:",
- "linkstoimage-more": "$1-ннел дуккхагIа {{PLURAL:$1|оагIув}} я укх файла тIахьожавеш.\nУкх хьаязъяьра чу белгалъяй цу файла {{PLURAL:$1|алхха $1 тIахьожаярг}}.\nТIакхача йиш я иштта [[Special:WhatLinksHere/$2|бIарчча хьаязъяьра]].",
+ "linkstoimage-more": "$1-ннел дуккхагIа {{PLURAL:$1|оагIув}} я укх файлá тIахьожавеш.\nУкх хьаязъяьра чу хьахьекхаб цу файла алхха {{PLURAL:$1|$1 тIатовжам}}.\nЦхьабакъда [[Special:WhatLinksHere/$2|бIарчча хьаязъяьра]] а тIакхача йиш я хьа.",
"nolinkstoimage": "Укх файла тӏатовжаш оагӏонаш яц.",
"linkstoimage-redirect": "$1 (файлови дӀа-хьа хьожавар) $2",
"sharedupload": "Ер файл $1 чура я, из пайда эцаш лелае мегаш я кхыйола проекташ чу.",
"sharedupload-desc-here": "Ер файл $1 чура я, иштта кхыйола проекташ чу пайда эца аьттув болаш я.\nЦун [$2 сурт оттадара оагIон] хоам кIалхахь хьабоалабаьб.",
"filepage-nofile": "Ишта цӀи йола файл йоацаш я.",
- "uploadnewversion-linktext": "ЧÑ\83Ñ\8fккÑ\85а Ñ\83кÑ\85 Ñ\84айла кеÑ\80да веÑ\80Ñ\81и",
+ "uploadnewversion-linktext": "Ð¥Ñ\8cаÑ\87Ñ\83Ñ\8fккÑ\85а Ñ\83кÑ\85 Ñ\84айла кеÑ\80да Ñ\8dÑ\80Ñ\88",
"upload-disallowed-here": "Хьа бокъо яц ер файл юха дӀаязъе.",
"filerevert-comment": "Бахьан:",
"filedelete-comment": "Бахьан:",
"filedelete-reason-otherlist": "Кхыдола бахьан",
"download": "хьачуяккха",
"unwatchedpages": "Цхьанне а зем беш йоаца оагIонаш",
- "randompage": "Ца ховш нийсъенна статья",
- "statistics": "СÑ\82аÑ\82иÑ\81Ñ\82ика",
+ "randompage": "Цаховш нийсъенна статья",
+ "statistics": "Ð\93Ó\80Ñ\83лакÑ\85-Ñ\85Ñ\8cал",
"statistics-articles": "Статьяш",
"statistics-pages": "ОагIонаш",
- "double-redirect-fixer": "Ð\94Ó\80а-Ñ\81аÑ\85Ñ\8cожадаÑ\80аÑ\88 Ñ\82оадер",
+ "double-redirect-fixer": "Ð\94Ó\80а-Ñ\85Ñ\8cа Ñ\85Ñ\8cожаваÑ\80а оагIонаÑ\88 Ñ\82оаер",
"brokenredirects-edit": "нийсъе",
"brokenredirects-delete": "дӀаяккха",
"withoutinterwiki-submit": "Хьахьокха",
"movethispage": "ЦIи хувца укх оагIон",
"pager-newer-n": "$1 дукхагIа {{PLURAL:$1|керда}}",
"pager-older-n": "{{PLURAL:$1|къаьнара дара|къаьнара дараш|къаьнара долaчарех}} $1",
- "booksources": "Ð\94жейнай Ñ\85Ñ\8cаÑ\81Ñ\82аÑ\88 (иÑ\81Ñ\82оÑ\87ники)",
+ "booksources": "Ð\9aинижкий Ñ\85Ñ\8cаÑ\81Ñ\82аÑ\88",
"booksources-search-legend": "Джейнах лаьца хоам лахар",
"booksources-search": "Хьалáха",
"specialloguserlabel": "Доакъашхо:",
"speciallogtitlelabel": "Эшар (цӀи е доакъашхо):",
"log": "Тептараш",
"all-logs-page": "Деррига тIакхача йиш йола тептараш",
- "alllogstext": "{{SITENAME}} Ñ\81айÑ\82а Ñ\82епÑ\82аÑ\80ий Ñ\8eкÑ\8aаÑ\80а Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80.\nÐ¥Ñ\8cа йиÑ\88 Ñ\8f Ñ\85Ñ\8cаÑ\85иннаÑ\80 Ñ\85Ñ\8cаÑ\85аÑ\80жа Ñ\82епÑ\82аÑ\80а Ñ\82айпаÑ\85, доакÑ\8aаÑ\88Ñ\85оÑ\87Ñ\83н Ñ\86IеÑ\80а Ñ\82айпаÑ\85 (Ñ\80егиÑ\81Ñ\82Ñ\80 лоаÑ\80Ñ\85IаÑ\88 Ñ\8f) е Ñ\85Ñ\8cаÑ\85аÑ\8fÑ\8cÑ\87а оагIон Ñ\82айпаÑ\85 (Ñ\80егиÑ\81Ñ\82Ñ\80 лоаÑ\80Ñ\85IаÑ\88 Ñ\8f).",
+ "alllogstext": "{{SITENAME}} Ñ\8fÑ\85аÑ\87а Ñ\81айÑ\82а Ñ\82епÑ\82аÑ\80ий Ñ\8eкÑ\8aаÑ\80а Ñ\85Ñ\8cаÑ\8fзÑ\8aÑ\8fÑ\8cÑ\80.\nÐ¥Ñ\8cалеÑ\85аÑ\80аÑ\88 кÑ\8aеÑ\80да йиÑ\88 Ñ\8f Ñ\82епÑ\82аÑ\80а Ñ\82айпаÑ\85, доакÑ\8aаÑ\88Ñ\85оÑ\87Ñ\83н Ñ\86IеÑ\80аÑ\85 (Ñ\80егиÑ\81Ñ\82Ñ\80 лоаÑ\80Ñ\85IаÑ\88 Ñ\8f) е Ñ\85Ñ\8cоаÑ\85аÑ\8fÑ\8cÑ\87а оагIонаÑ\85 (Ñ\83кÑ\85аза а иÑ\88Ñ\82Ñ\82а Ñ\80егиÑ\81Ñ\82Ñ\80 лоаÑ\80Ñ\85I).",
"logempty": "Укх оагӀон дӀаяздаьраш тептара чу дац.",
"allpages": "Еррига оагIонаш",
"prevpage": "Хьалха йоагIа оагIув ($1)",
- "allpagesfrom": "Ð¥Ñ\8cаÑ\85Ñ\8cокÑ\85а оагÓ\80онаÑ\88 дӀайолалуш йола укх алапех:",
+ "allpagesfrom": "Ð\93Ñ\83Ñ\87аÑ\8fÑ\85а оагÓ\80онаÑ\88, дӀайолалуш йола укх алапех:",
"allpagesto": "Хьахьокхар соцадé укхун тӀа:",
"allarticles": "Еррига оагIонаш",
"allpagessubmit": "Кхоачашде",
- "allpages-hide-redirects": "Ð\9aÑ\8aайладаÑ\85а дÓ\80а-Ñ\81аÑ\85Ñ\8cожадараш",
+ "allpages-hide-redirects": "Ð\94IакÑ\8aайладаÑ\85а дÓ\80а-Ñ\85Ñ\8cа Ñ\85Ñ\8cожавераш",
"categories": "ОагIаташ",
"linksearch": "Арахьара тIахьожаяргаш лахар",
"linksearch-ns": "ЦIерий аренаш:",
- "linksearch-ok": "Хьалáха",
- "linksearch-line": "$2 — тIахьожаярг укхаз $1",
+ "linksearch-ok": "Хьалаха",
+ "linksearch-line": "$1 яхача оагIонна тIатовжам $2 чура",
"listgrouprights-members": "(доакъашхой хьаязъяьр)",
"listgrouprights-namespaceprotection-namespace": "ЦIерий аре",
"emailuser": "Доакъашхочоа каьхат",
"watchlist-details": "Хьа зем бара хьаязъяьр чу $1 {{PLURAL:$1|оагIув}} я (иштта дувца оттадара оагIонаш а).",
"wlheader-showupdated": "Хувцаенна оагIонаш '''сома''' шрифтаца белгалъяьй.",
"wlnote": "КIалха хьагойт {{PLURAL:$2|тIехьарча сахьата|тIехьарча <strong>$2</strong> сахьата}} даь хинна {{PLURAL:$1|тIеххьара хувцам|тIеххьара <strong>$1</strong> хувцам}} ($3 $4).",
- "wlshowlast": "Хьахьокха тIехьара $1 сахьатах $2 дийнахь",
+ "wlshowlast": "Хьахьокха тIехьарча $2 ден $1 сахьатá",
"watchlist-options": "Зем бара хьаязъяьра тоадараш",
"watching": "Зем бара хьаязъяьр чу тIатохар",
"unwatching": "Зем бара хьаязъяьр чура дIадаккхар",
"rollbacklinkcount": "юхататта $1 {{PLURAL:$1|нийсдар}}",
"protectlogpage": "ГIон тептар",
"protectedarticle": "Лораяьй оагӀув «[[$1]]»",
- "modifiedarticleprotection": "Лорадара лагIа хийцад оагIон «[[$1]]»",
+ "modifiedarticleprotection": "Лорадара лагIа хийцад «[[$1]]» яхача оагIон",
"protectcomment": "Бахьан:",
"protectexpiry": "Чакхдоала:",
"protect_expiry_invalid": "Лорадар чакхадоала харцахьа ха",
"whatlinkshere": "Тӏатовжамаш укхаза",
"whatlinkshere-title": "«$1» яхача оагӏонна тӏатовжаш йола оагӏонаш",
"whatlinkshere-page": "ОагIув:",
- "linkshere": "«'''[[:$1]]'''» яхача оагIонна тIахьожавеш я тIехьайоагIа:",
+ "linkshere": "«'''[[:$1]]'''» ← укхунна тӀахьожавеш я тӀехьайоагӀа оагӀонаш:",
"nolinkshere": "Кхыйолча оагӏонашкара '''[[:$1]]''' яхача оагӏон тIатовжамаш доацаш да.",
- "isredirect": "оагIÑ\83в-дIа-Ñ\81аÑ\85Ñ\8cожадаÑ\80",
+ "isredirect": "дIа-Ñ\85Ñ\8cа Ñ\85Ñ\8cожаваÑ\80а оагIÑ\83в",
"istemplate": "юкъейоалаяр",
"isimage": "Файлови тӏатовжам",
"whatlinkshere-prev": "{{PLURAL:$1|1=хьалхайоагIа|хьалхайоагIараш}} $1",
"whatlinkshere-hideredirs": "$1 дӀа-хьа хьожавараш",
"whatlinkshere-hidetrans": "$1 юкъедоаладаьраш",
"whatlinkshere-hidelinks": "$1 тӏатовжамаш",
- "whatlinkshere-hideimages": "$1 Ñ\84айлай Ñ\82IаÑ\85Ñ\8cожаÑ\8fÑ\80гаш",
+ "whatlinkshere-hideimages": "$1 Ñ\84айлай Ñ\82IаÑ\82овжамаш",
"whatlinkshere-filters": "Фильтраш",
"blockip": "ЧIега тоха {{GENDER:$1|доакъашхочун}}",
"ipboptions": "2 сахьат:2 hours,1 ди:1 day,3 ди:3 days,1 кIира:1 week,2 кIира:2 weeks,1 бутт:1 month,3 бутт:3 months,6 бутт:6 months,1 шу:1 year,хоадаяь ха йоаца:infinite",
"importlogpage": "Импорта тептар",
"tooltip-pt-userpage": "{{GENDER:|Хьа}} доакъашхочун оагIув",
"tooltip-pt-mytalk": "{{GENDER:|Хьа}} дувца оттадара оагIув",
- "tooltip-pt-preferences": "{{GENDER:|Ð¥Ñ\8cа гIиÑ\80Ñ\81аш}}",
+ "tooltip-pt-preferences": "{{GENDER:|Ð¥Ñ\8cа оÑ\82Ñ\82амаш}}",
"tooltip-pt-watchlist": "Iа зем бу оагIонаш",
"tooltip-pt-mycontris": "{{GENDER:|хьа}} хувцамаш",
"tooltip-pt-login": "Укхаза хьай цIи аьле чувала/яла йиша я, амма из параз дац",
"tooltip-pt-logout": "Аравала/яла",
- "tooltip-pt-createaccount": "Хьа бокъо я дагара йоазув кхелла система чувала, амма параз долаш дац из.",
- "tooltip-ca-talk": "Ð\9eагIон Ñ\87Ñ\83даÑ\80 дÑ\83вÑ\86а оÑ\82Ñ\82адар",
+ "tooltip-pt-createaccount": "Хьа бокъо я дагара йоазув хьа а кхелла ражача чувала.",
+ "tooltip-ca-talk": "Ð\9eагIон Ñ\87Ñ\83лоаÑ\86амаÑ\85 лаÑ\8cÑ\86а дÑ\83вÑ\86ар",
"tooltip-ca-edit": "Нийсъе ер оагIув",
"tooltip-ca-addsection": "Керда дáкъа хьаде",
- "tooltip-ca-viewsource": "Ер оагIув хувцамбарах гIо теха (лорая) я, амма цунна дIадолалу текстага хьажа а, из тIерхьаязъе а бокъо я.",
+ "tooltip-ca-viewsource": "Ер оагIув хувца йиш хургьйоацаш лораяь я, амма цун чухьнахьарча текстага хьажа а из тIера хьаязъе а вIаштехьа да.",
"tooltip-ca-history": "Укх оагIон даь хувцамаш тIа дола тептар",
"tooltip-ca-protect": "Лорае ер оагIув хувцамаш дергдоацаш",
"tooltip-ca-delete": "ДӀаяккха ер оагӀув",
"tooltip-ca-move": "Укх оагӀон цӀи хувца",
- "tooltip-ca-watch": "ТIатоха ер оагIув хьа зем бара хьаязъяьра",
+ "tooltip-ca-watch": "ТIатоха ер оагIув хьай зéма хьаязъяьрá",
"tooltip-ca-unwatch": "ДӀаяккха ер оагӀув шоай зема хьаязъяьра тIара",
"tooltip-search": "Хьалáха {{grammar:prepositional|{{SITENAME}}}} чу",
"tooltip-search-go": "Изза мо цӀи йолаш оагӀон тӀa дехьавала",
"tooltip-n-randompage": "Башхало йоаца ца ховш нийсъенна оагӀув хьаела",
"tooltip-n-help": "Новкъостал лаха мегаш йола моттиг",
"tooltip-t-whatlinkshere": "Укхаза тӏатовжаш йола оагӏонаш",
- "tooltip-t-recentchangeslinked": "УкÑ\85 оагIо Ñ\82IаÑ\85Ñ\8cожавеÑ\88 йолÑ\87а оагIонай Ñ\82IеÑ\85хьара хувцамаш",
+ "tooltip-t-recentchangeslinked": "Ð\95Ñ\80 оагIÑ\83в Ñ\82IаÑ\82овжаÑ\88 йолÑ\87а оагIонаÑ\88 Ñ\87Ñ\83Ñ\80а Ñ\82Iехьара хувцамаш",
"tooltip-feed-rss": "RSS чу гойтар укх оагIон",
"tooltip-feed-atom": "Укх оагIонна лаьрххIа Atom чу трансляци яр",
"tooltip-t-contributions": "{{GENDER:$1|Укх доакъашхочо хийца}} йола оагIонаш",
- "tooltip-t-emailuser": "ДIахьийта каьхат {{GENDER:$1|укх доакъашхочун}}",
+ "tooltip-t-emailuser": "ДIадахьийта каьхат {{GENDER:$1|укх доакъашхочунга}}",
"tooltip-t-upload": "Файлаш чуяккха",
"tooltip-t-specialpages": "ГIулакха оагIонаш",
"tooltip-t-print": "Укх оагӏон зарба тохара эрш",
"tooltip-ca-nstab-category": "ОагIата оагӀув",
"tooltip-minoredit": "Ер хувцар кIезига дар санна белгалде",
"tooltip-save": "Хьа хувцамаш лорадеш дIаязде",
- "tooltip-preview": "Ð\94еÑ\85аÑ\80 да, оагÓ\80Ñ\83в лоÑ\80аеÑ\88Ñ\8c дIаÑ\8fзÑ\8aелеÑ\85Ñ\8c из миÑ\88Ñ\82а Ñ\8f Ñ\82аÑ\85ка Ñ\85Ñ\8cалÑ\85Ñ\85е бIаÑ\80гÑ\82оÑ\85аÑ\80аÑ\85 пайда Ñ\8dÑ\86аÑ\88!",
+ "tooltip-preview": "Ð\9eагIонна Ñ\85Ñ\8cалÑ\85Ñ\85е бIаÑ\80гÑ\82оÑ\85аÑ\80.\nÐ\94еÑ\85аÑ\80 да, оагÓ\80Ñ\83в дIаÑ\8fзÑ\8aелеÑ\85Ñ\8c Ñ\85Ñ\8cажа из миÑ\88Ñ\82а Ñ\8f!",
"tooltip-diff": "ДIадолалу текстаца даь хувцамаш хьахьокха",
"tooltip-compareselectedversions": "Укх оагIон хержа шин версешта юкъе йола башхалога хьажа.",
"tooltip-watch": "ТIатоха ер оагIув хьа зем бара хьаязъяьра",
- "tooltip-rollback": "ЦкÑ\8aа пIелг Ñ\82оIабе дIадаккÑ\85а Ñ\82IеÑ\85Ñ\8cаÑ\80а Ñ\80едакÑ\82оÑ\80аÑ\81 даь хувцамаш",
+ "tooltip-rollback": "ЦкÑ\8aа пIелг Ñ\82оIабаÑ\8c дIадаÑ\85а Ñ\82IеÑ\85Ñ\8cаÑ\80Ñ\87а Ñ\80едакÑ\82оÑ\80о даь хувцамаш",
"tooltip-undo": "Даь хувцар дIадаьккха, хьалххе бIаргтохар хьахьокха, дIадаккхара бахьан Iочуязде аьттув болаш.",
"tooltip-summary": "Лоаца сурт оттадар Iочуязде",
"simpleantispam-label": "Анти-спам тахкар.\n<strong>Цхьа</strong> хIама ма язъе укхаз!",
"pageinfo-few-watchers": "{{PLURAL:$1|Зем бер}} $1-ннел кIезигагIа ба",
"pageinfo-redirects-name": "Укх оагӀонна дӀа-сахьожадарий дуккхал",
"pageinfo-subpages-name": "Укх оагӀон кIалоагӀонаш",
- "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|дIа-Ñ\81аÑ\85Ñ\8cожадаÑ\80}}; $3 {{PLURAL:$3|обÑ\8bÑ\87наÑ\8f|обÑ\8bÑ\87нÑ\8bе|обÑ\8bÑ\87нÑ\8bÑ\85}})",
+ "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|дIа-Ñ\85Ñ\8cа Ñ\85Ñ\8cожаÑ\8fÑ\8cÑ\80}}; $3 {{PLURAL:$3|кÑ\85Ñ\8bÑ\8fÑ\80}})",
"pageinfo-firstuser": "ОагӀув кхеллар",
- "pageinfo-firsttime": "ОагӀув кхелла хинна таьрахь",
+ "pageinfo-firsttime": "ОагӀув кхелла хинна ди",
"pageinfo-lastuser": "ТӀехьара хувцам баьр",
"pageinfo-lasttime": "ТӀехьара нийсдар даь хинна таьрахь",
"pageinfo-edits": "Дерригача нийсдарий дукхал",
"metadata": "Мета-дараш",
"metadata-help": "Файло кхыдола дараш чулоаца, цифровой суртдоакхарго е сканеро тIатохаш дола. Нагахьа файл чуякхачул тIехьа хийца хинна дале, цхьаццайола параметраш хIанзара сурта тIара йоацаш хила мегаш я.",
"metadata-expand": "Хьахьокха кхыдола дараш",
- "metadata-collapse": "Ð\9aÑ\8aайладаккха кхыдола дараш",
+ "metadata-collapse": "Ð\94IакÑ\8aайладаха кхыдола дараш",
"metadata-fields": "Укх хьаяьзъяра чу дагaрадаь суртий метахоамий йистош, хьахьекха хургда сурта оагIон тIа, хьоарчадаь метахоамий ильг долаш. Юхедиса йистош къайла хургда.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
"exif-imagewidth": "Шерал",
"exif-imagelength": "Лакхал",
"exif-orientation": "Сурта белгало",
"exif-xresolution": "ПхьорагIа тIера боарам",
"exif-yresolution": "УрагIа тIера боарам",
- "exif-datetime": "Файл хийца хинна таьрахьи хаи",
+ "exif-datetime": "Файл хийца хинна дии хаи",
"exif-imagedescription": "Сурта цIи",
"exif-make": "Камера кийчъяь арахийцар",
"exif-model": "Камера модель",
"watchlisttools-raw": "Массаза йола текст санна хувца",
"signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|дувца оттадар]])",
"duplicate-defaultsort": "Теркам. Долча тайпара дIанийсдара дIоагIа «$2» юхакъоастаду долча тайпара дIанийсдара хьалха хинна дIоагIа «$1».",
- "version": "Ð\92еÑ\80Ñ\81и",
+ "version": "ÐÑ\80Ñ\88",
"version-specialpages": "ГIулакха оагӀонаш",
"version-version": "($1)",
- "version-software-version": "Ð\92еÑ\80Ñ\81и",
- "redirect": "Файла идентификатора тIара, доакъашхочун тIара, оагIон тIара, версин е тептара тIара дIа-сахьожадар",
- "redirect-summary": "Укх белха оагIо дIа-сахьожаву файла (файлан цIера тIара), оагIонна (оагIон тIара е оагIон эрша идентификатора тIара), доакъашхочун оагIонна (доакъашхочун таьрахьа идентификатора тIара) е тептара йоазонна (тептара идентификатора тIара). Пайда эцар: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]] или [[{{#Special:Redirect}}/logid/186]].",
+ "version-software-version": "ÐÑ\80Ñ\88",
+ "redirect": "Файла идентификатора тIара, доакъашхочун тIара, оагIон тIара, эрша тIара е тептара тIара дIа-хьа хьожавар",
+ "redirect-summary": "Укх белха оагIоно дIа-хьа хьожаву файлá (файла цIера тIара), оагIонна (оагIон тIара е оагIон эрша идентификатора тIара), доакъашхочун оагIонна (доакъашхочун таьрахьа идентификатора тIара) е тептара йоазонна (тептара идентификатора тIара). Пайда эцар: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]] или [[{{#Special:Redirect}}/logid/186]].",
"redirect-submit": "Дехьавала",
"redirect-lookup": "Лахар:",
"redirect-value": "Боарам:",
"tags-title": "Белгалонаш",
"tags-tag": "Белгалон цӀи",
"tags-hitcount-header": "Белгалдаь нийсдараш",
- "tags-active-yes": "XIаа",
+ "tags-active-yes": "XӀау",
"tags-active-no": "A",
"tags-edit": "нийсде",
"tags-hitcount": "$1 {{PLURAL:$1|1=хувцам|хувцамаш}}",
"tags-create-submit": "Хьакхолла",
"compare-page1": "ЦхьоаллагIа оагIув",
"compare-page2": "ШоллагIа оагӀув",
- "compare-rev1": "ЦÑ\85Ñ\8cоаллагIа веÑ\80Ñ\81и",
- "compare-rev2": "ШоллагӀа верси",
+ "compare-rev1": "Ð¥Ñ\8cалÑ\85аÑ\80а Ñ\8dÑ\80Ñ\88",
+ "compare-rev2": "ШоллагӀа эрш",
"htmlform-submit": "ДIадахьийта",
"htmlform-reset": "Хувцамаш юхадаккха",
"htmlform-selectorother-other": "Кхыдар",
"logentry-newusers-create": "{{GENDER:$2|Доакъашхочо хьакхеллад}} дагара йоазув $1",
"logentry-newusers-autocreate": "Ше-ше кхеллай {{GENDER:$2|доакъашхочун}} $1 дагара йоазув",
"logentry-upload-upload": "$1 {{GENDER:$2|чуяьккхай}} $3",
- "logentry-upload-overwrite": "$1 доакъашхочо {{GENDER:$2|чуяьккхай}} керда верси $3",
+ "logentry-upload-overwrite": "$1 доакъашхочо {{GENDER:$2|чуяьккхай}} $3 яхачун керда эрш",
"rightsnone": "(яц)",
"searchsuggest-search": "Хьалаха {{grammar:prepositional|{{SITENAME}}}} чу",
"duration-days": "{{PLURAL:$1|ди}}",
"expand_templates_preview": "Хьалххе бIаргтохар",
"pagelang-name": "ОагIув",
- "special-characters-group-latin": "Ð\9bаÑ\82иной",
+ "special-characters-group-latin": "Ð\9bаÑ\82иний",
"special-characters-group-greek": "Эллиной",
"special-characters-group-cyrillic": "Кириллица",
"special-characters-group-arabic": "Iарбий",
"preview": "Previdar",
"showpreview": "Previdar",
"showdiff": "Montrez chanji",
- "blankarticle": "<strong>Averto:</strong> La pagino vu kreas es vakua.\nSe vu ri-selektos \"$1\", la pagino kreesos sen irga kontenajo.",
+ "blankarticle": "<strong>Averto:</strong> La pagino quon vu kreis es vakua.\nSe vu ri-selektos \"$1\", la pagino kreesos sen irga kontenajo.",
"anoneditwarning": "<strong>Averto:</strong> Vu ne eniris.\nVua IP-adreso esos videbla publike se vu redaktos. Se vu <strong>[$1 enirus]</strong> od <strong>[$2 kreus konto]</strong>, vua redakti atribuesos a vua uzeronomo, kune kun altra bonaji.",
"anonpreviewwarning": "<em>Vu ne eniris. Konservar chanji registragos vua IP-adreso en la redakto-historio di ta pagino.</em>",
"missingcommenttext": "Voluntez skribar komento.",
"permissionserrorstext-withaction": "Vu ne darfas $2, pro la {{PLURAL:$1|kauzo|kauzi}} sequanta:",
"recreate-moveddeleted-warn": "<strong>Atencez: Vu rikreos pagino qua antee efacesis.</strong>\n\nVu mustas konsiderar se esos konvenanta o ne riskribor ol.\nPor vua konoco, la motivo dil antea efaco montresas hike:",
"moveddeleted-notice": "Ica pagino efacesis.\nL'efaco-registraro e la movo-registraro di la pagino povas videsar sequante, por konsulto.",
+ "moveddeleted-notice-recent": "Pardonez, ica pagino efacesis recente (dum la lasta 24 hori).\nL'informo (log) pri l'efaco, la protektado e/o movo di la pagino povas videsar adinfre, por konsulto.",
"log-fulllog": "Videz kompleta protokolo ('log')",
"edit-conflict": "Konflikto di editi.",
"postedit-confirmation-created": "La pagino kreesis.",
"rcfilters-days-title": "Recenta dii",
"rcfilters-hours-title": "Recenta hori",
"rcfilters-days-show-days": "$1 {{PLURAL:$1|dio|dii}}",
+ "rcfilters-days-show-hours": "$1 {{PLURAL:$1|horo|hori}}",
"rcfilters-quickfilters": "Konservita filtrili",
"rcfilters-quickfilters-placeholder-title": "Nula filtrilo konservesis til nun",
"rcfilters-savedqueries-defaultlabel": "Konservita filtrili",
"filesource": "Fonto:",
"ignorewarning": "Ignorar la averto e gardar la arkivo irgakaze.",
"badfilename": "La imajo-nomo chanjesis a \"$1\".",
+ "empty-file": "L'arkivo sendita da vu esas vakua.",
"fileexists": "Arkivo kun ta nomo ja existas.\nVolutez kontrolar <strong>[[:$1]]</strong> se {{GENDER:|vu}} ne esas certa pri chanjar olu.\n[[$1|thumb]]",
"filepageexists": "La pagino kun deskripto pri ica arkivo ja kreesis en <strong>[[:$1]]</strong>, tamen nul arkivo kun ica nomo existas ankore.\nLa rezumo pri ol quon vu skriptis ne aparos en la deskripto-pagino.\nPor ke la rezumo aparos ibe, vu mustos <strong>skribor ol manuale.</strong>\n[[$1|thumb]]",
"uploadwarning": "Averto pri la adkargo di arkivo",
"withoutinterwiki": "Pagini sen linguo-ligili",
"withoutinterwiki-legend": "Prefixo",
"withoutinterwiki-submit": "Montrar",
+ "fewestrevisions": "Pagini kun poka revizi",
"nbytes": "$1 {{PLURAL:$1|bicoko|bicoki}}",
"ncategories": "$1 {{PLURAL:$1|kategorio|kategorii}}",
"nlinks": "$1 {{PLURAL:$1|ligilo|ligili}}",
"booksources-search-legend": "Serchez librala fonti",
"booksources-search": "Serchar",
"booksources-text": "Infre vu povas vidar listo di ligili ad altra retsitui qui vendas nova ed uzata libri, ed anke povas havar informi pri la libri quin vu serchabas:\nLa {{SITENAME}} ne mantenas komercala relati kun ta vendeyi mencionata, e la listo ne povas konsideresar rekomendo o vend-anunco.",
+ "magiclink-tracking-pmid-desc": "Ica pagino uzas magiala ligili PMID. Videz [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] pri quale migrar.",
"magiclink-tracking-isbn": "Pagini qui uzas ligili ISBN",
"specialloguserlabel": "Agero:",
"speciallogtitlelabel": "Skopo (titulo od {{ns:user}}:uzernomo por uzero):",
"listgrouprights": "Permisi dil grupo di uzeri",
"listgrouprights-group": "Grupo",
"listgrouprights-members": "(listo di membri)",
+ "trackingcategories": "Kategorii por kontrolo",
+ "trackingcategories-name": "Nomo di la mesajo",
+ "trackingcategories-desc": "Kriterii por inkluzar kategorii",
"restricted-displaytitle-ignored-desc": "La pagino havas nekonocita titulo <code><nowiki>{{DISPLAYTITLE}}</nowiki></code>, pro ol ne esas equivalanta a la nuna titulo di ica pagino.",
"mailnologin": "Ne sendar adreso",
"mailnologintext": "Vu mustas [[Special:UserLogin|enirir]] e havar valida e-adreso en vua [[Special:Preferences|preferaji]] por sendar e-posto ad altra uzanti.",
"protect-othertime-op": "altra tempo",
"protect-otherreason": "Altra/suplementala motivo:",
"protect-otherreason-op": "Altra motivo",
+ "protect-dropdown": "*Frequa motivi por protektado\n** Intensa vandalismo\n** Intensa atako per 'spam'\n** Redakto-milito neutila\n** Pagino multe vizitata",
"protect-expiry-options": "1 horo:1 hour,1 dio:1 day,1 semano:1 week,2 semani:2 weeks,1 monato:1 month,3 monati:3 months,6 monati:6 months,1 yaro:1 year,nefinita:infinite",
"restriction-type": "Permiso:",
"pagesize": "(bicoki)",
"newimages-legend": "Filtrilo",
"ilsubmit": "Serchar",
"bydate": "per dato",
+ "hours": "{{PLURAL:$1|$1 horo|$1 hori}}",
"days": "{{PLURAL:$1|$1 dio|$1 dii}}",
"weeks": "{{PLURAL:$1|$1 semano|$1 semani}}",
"months": "{{PLURAL:$1|$1 monato|$1 monati}}",
"logentry-patrol-patrol-auto": "$1 automatale {{GENDER:$2|indikis}} ke la revizo $4 de la pagino $3 surveyesas",
"logentry-newusers-create": "La konto dil uzero $1 kreesis.",
"logentry-newusers-autocreate": "L'uzanto $1 {{GENDER:$2|kreesis}} automatale",
+ "logentry-protect-protect": "$1 protektis la pagino $3 $4",
"logentry-protect-modify": "$1 {{GENDER:$2|modifikis}} la nivelo di protekto por $3 $4",
"logentry-protect-modify-cascade": "$1 {{GENDER:$2|modifikis}} la nivelo di protekto di $3 $4 [kaskade]",
"logentry-upload-upload": "$1 {{GENDER:$2|uploaded}} $3",
"rcfilters-filter-reviewstatus-unpatrolled-label": "Non verificate",
"rcfilters-filter-reviewstatus-manual-description": "Modifiche contrassegnate manualmente come verificate.",
"rcfilters-filter-reviewstatus-manual-label": "Verificato manualmente",
- "rcfilters-filter-reviewstatus-auto-description": "Le modifiche degli utenti esperti il cui lavoro sarà automaticamente marcato come esaminato.",
+ "rcfilters-filter-reviewstatus-auto-description": "Le modifiche degli utenti esperti saranno automaticamente marcate come verificate.",
"rcfilters-filter-reviewstatus-auto-label": "Autoverificato",
"rcfilters-filtergroup-significance": "Significato",
"rcfilters-filter-minor-label": "Modifiche minori",
"prefs-dateformat": "日付と時刻の形式",
"prefs-timeoffset": "時差",
"prefs-advancedediting": "全般オプション",
+ "prefs-developertools": "開発者用ツール",
"prefs-editor": "エディター",
"prefs-preview": "プレビュー",
"prefs-advancedrc": "詳細の設定",
"recentchangeslinked-feed": "가리키는 글의 최근 바뀜",
"recentchangeslinked-toolbox": "가리키는 글의 최근 바뀜",
"recentchangeslinked-title": "\"$1\" 문서에 관련된 문서 바뀜",
- "recentchangeslinked-summary": "해당 문서에 연결된 문서의 변경사항을 확인하려면 문서 이름을 입력하십시오. (분류에 들어있는 문서를 보려면 분류:분류명으로 입력하십시오). [[Special:Watchlist|내 주시문서 목록]]에 있는 문서의 변경사항은 <strong>굵게</strong> 나타납니다.",
+ "recentchangeslinked-summary": "해당 문서에 연결된 문서의 변경사항을 확인하려면 문서 이름을 입력하십시오. (분류에 들어있는 문서를 보려면 {{ns:category}}:분류명으로 입력하십시오). [[Special:Watchlist|내 주시문서 목록]]에 있는 문서의 변경사항은 <strong>굵게</strong> 나타납니다.",
"recentchangeslinked-page": "문서 이름:",
"recentchangeslinked-to": "해당 문서를 가리키는 문서의 최근 바뀜 보기",
"recentchanges-page-added-to-category": "[[:$1]]에 분류를 추가하였습니다",
"savearticle": "Sjlaon pagina op",
"savechanges": "Verangeringe opsjlaon",
"publishpage": "Pagina publicere",
- "publishchanges": "Verangeringe publicere",
+ "publishchanges": "Sjlaon verangeringe op",
"savearticle-start": "Sjlaon pagina op...",
"savechanges-start": "Sjlaon verangeringe op...",
"publishpage-start": "Bring pagina oet...",
"listduplicatedfiles": "Lies mit bestenj mit duplikaote",
"listduplicatedfiles-summary": "Dit is 'n lies mit bestenj wovan de litste versie e duplikaot is van de recènste versie van 'n anger bestandj. Allein weurt gerapporteerd euver lokaal bestenj.",
"listduplicatedfiles-entry": "[[:File:$1|$1]] haet [[$3|{{PLURAL:$2|ei duplikaot|$2 duplikaote}}]].",
- "unusedtemplates": "Óngerbroekde sjablone",
+ "unusedtemplates": "Óngebroekde sjablone",
"unusedtemplatestext": "Deze pagina guf alle pagina's weer in de {{nas:template}}naamruumde die op gein inkele pagina gebroek waere. Vergaet neet de \"Links nao deze pagina\" te controlere veures dit sjabloon te wösse.",
"unusedtemplateswlh": "anger links",
"randompage": "Willekäörige pagina",
"tooltip-ca-nstab-category": "Betrach de categoriepagina",
"tooltip-minoredit": "Markeer dit es 'n klein verangering",
"tooltip-save": "Bewaar dien verangeringe",
- "tooltip-publish": "Verangeringe publicere",
+ "tooltip-publish": "Sjlaon dien verangeringe op",
"tooltip-preview": "Betrach dien verangeringe veurdets te ze definitief opsjleis!",
"tooltip-diff": "Betrach dien verangeringe in de teks.",
"tooltip-compareselectedversions": "Betrach de versjille tösje de twie geselecteerde versies van dees pagina.",
"confirm-purge-title": "Vernuuj dees pagina",
"confirm_purge_button": "ok",
"confirm-purge-top": "Wils te de buffer vaan dees paas wisse?",
- "confirm-purge-bottom": "t Opsjone van de cache zorg drveur det de lèste versie van n pagina wörd weergegaeve.",
+ "confirm-purge-bottom": "'t Opsjeune van de cache zorg d'rveur det de lèste versie van 'n pagina weurt getuind.",
"confirm-watch-button": "Ok",
"confirm-watch-top": "Dees pagina bie dien volglies zètte?",
"confirm-unwatch-button": "Ok",
"savechanges": "Išsaugoti pakeitimus",
"publishpage": "Išsaugoti puslapį",
"publishchanges": "Išsaugoti pakeitimus",
+ "savearticle-start": "Išsaugoti puslapį…",
+ "savechanges-start": "Išsaugoti pakeitimus…",
+ "publishpage-start": "Išsaugoti puslapį…",
+ "publishchanges-start": "Išsaugoti pakeitimus…",
"preview": "Peržiūra",
"showpreview": "Rodyti peržiūrą",
"showdiff": "Rodyti skirtumus",
"previewnote": "<strong>Nepamirškite, kad tai tik peržiūra, pakeitimai dar nėra išsaugoti!</strong>",
"continue-editing": "Eiti į redagavimo sritį",
"previewconflict": "Ši peržiūra parodo tekstą iš viršutiniojo teksto redagavimo lauko taip, kaip jis bus rodomas, jei pasirinksite išsaugoti.",
- "session_fail_preview": "'''Atsiprašome! Mes negalime vykdyti jūsų keitimo dėl sesijos duomenų praradimo.\nPrašome pamėginti vėl. Jei tai nepadeda, pamėginkite atsijungti ir prisijungti atgal.'''",
+ "session_fail_preview": "Atsiprašome! Mes negalime vykdyti jūsų keitimo dėl sesijos duomenų praradimo.\n\nGali būti, kad esate atsijungęs. <strong>Prašome patikrinti, ar vis dar esate prisijungęs, ir pabandyti iš naujo</strong>. \nJei ir toliau nepavyksta, pamėginkite [[Special:UserLogout|atsijungti]] ir vėl prisijungti, taip pat patikrinkite, ar jūsų naršyklė priima šios svetainės slapukus.",
"session_fail_preview_html": "Atsiprašome! Mes negalime apdoroti jūsų keitimo dėl sesijos duomenų praradimo.\n\n<em>Kadangi {{SITENAME}} grynasis HTML yra įjungtas, peržiūra yra paslėpta kaip atsargumo priemonė prieš JavaScript atakas.</em>\n\n<strong>Jei tai teisėtas keitimo bandymas, prašome pamėginti vėl.</strong> Jei tai nepadeda, pamėginkite [[Special:UserLogout|atsijungti]] ir prisijungti atgal, ir patikrinkite ar jūsų naršyklė leidžia šiam tinklapiui naudoti slapukus.",
"token_suffix_mismatch": "'''Jūsų pakeitimas buvo atmestas, nes jūsų naršyklė iškraipė skyrybos ženklus keitimo žymėje. Keitimas buvo atmestas norint apsaugoti puslapio tekstą nuo sugadinimo. Taip kartais būna, kai jūs naudojate anoniminį tarpinio serverio paslaugą.'''",
"edit_form_incomplete": "'''Kai redaguoti formos dalys nepasiekė serverio; du kartus patikrinti, kad jūsų pakeitimai yra nesugadintos ir bandykite dar kartą.'''",
"undo-summary": "Atšauktas [[Special:Contributions/$2|$2]] ([[User talk:$2|Aptarimas]] | [[Special:Contributions/$2|{{MediaWiki:Contribslink}}]]) keitimas ($1 versija)",
"undo-summary-username-hidden": "Atmesti versiją $1, atliktą paslėpto naudotojo",
"cantcreateaccount-text": "Paskyrų kūrimą iš šio IP adreso ('''$1''') užblokavo [[User:$3|$3]].\n\n$3 nurodyta priežastis yra ''$2''",
- "cantcreateaccount-range-text": "Naudotojas [[User:$3|$3]] nustatė draudimą kurti paskyras iš IP adresų plotmės <strong>$1</strong>, į kurią patenka ir jūsiškis IP adresas (<strong>$4</strong>).",
+ "cantcreateaccount-range-text": "Naudotojas [[User:$3|$3]] nustatė draudimą kurti paskyras iš IP adresų plotmės <strong>$1</strong>, į kurią patenka ir jūsiškis IP adresas (<strong>$4</strong>).\n\n$3 nurodyta priežastis yra <em>$2</em>",
"viewpagelogs": "Rodyti šio puslapio specialiuosius veiksmus",
"nohistory": "Šis puslapis neturi keitimų istorijos.",
"currentrev": "Dabartinė versija",
"rollback-success": "Atmesti {{GENDER:$3|$1}} pakeitimai;\ngrąžinta prieš tai buvusi {{GENDER:$4|$2}} versija.",
"rollback-success-notify": "Atmesti $1 pakeitimai;\ngrąžinta prieš tai buvusi $2 versija. [$3 Rodyti skirtumus]",
"sessionfailure-title": "Sesijos klaida",
- "sessionfailure": "Atrodo yra problemų su jūsų prisijungimo sesija; šis veiksmas buvo atšauktas kaip atsargumo priemonė prieš sesijos vogimą.\nPrašome paspausti „atgal“ ir perkraukite puslapį iš kurio atėjote, ir pamėginkite vėl.",
+ "sessionfailure": "Atrodo yra problemų su jūsų prisijungimo sesija; šis veiksmas buvo atšauktas kaip atsargumo priemonė prieš sesijos vogimą.\nPrašome iš naujo pateikti formą.",
"changecontentmodel": "Keisti puslapio turinio modelį",
"changecontentmodel-legend": "Keisti turinio modelį",
"changecontentmodel-title-label": "Puslapio pavadinimas",
"log-action-filter-managetags-deactivate": "Žymės deaktyvavimas",
"log-action-filter-move-move": "Perkėlimai, nepakeičiant nukreipimų",
"log-action-filter-move-move_redir": "Perkėlimai, pakeičiant buvusius nukreipimus",
+ "log-action-filter-newusers-create": "Sukurta anoniminio naudotojo",
+ "log-action-filter-newusers-create2": "Sukurta registruoto naudotojo",
"log-action-filter-newusers-autocreate": "Automatinis kūrimas",
+ "log-action-filter-newusers-byemail": "Sukurta su slaptažodžiu, atsiųstu el. paštu",
"log-action-filter-patrol-patrol": "„Rankinis“ patikrinimas",
"log-action-filter-patrol-autopatrol": "Automatinis patikrinimas",
"log-action-filter-protect-protect": "Apsauga",
"rcfilters-liveupdates-button-title-off": "Rādīt jaunās izmaiņas, tiklīdz tās tiek veiktas",
"rcfilters-watchlist-markseen-button": "Atzīmēt visas izmaiņas kā apskatītas",
"rcfilters-watchlist-edit-watchlist-button": "Labot manu uzraugāmo lapu sarakstu",
- "rcfilters-watchlist-showupdated": "Izmaiņas lapās, kuras nav apmeklētas kopš izmaiņu veikšanas ir <strong>trekninātā rakstā</strong>.",
+ "rcfilters-watchlist-showupdated": "Izmaiņas lapās, kuras nav apmeklētas kopš izmaiņu veikšanas, ir <strong>trekninātā rakstā</strong>.",
"rcfilters-preference-label": "Paslēpt uzlaboto pēdējo izmaiņu versiju",
"rcnotefrom": "Zemāk {{PLURAL:$5|redzamas izmaiņas|redzama izmaiņa|redzamas izmaiņas}} kopš <strong>$3, $4</strong> (parādītas ne vairāk kā <strong>$1</strong>).",
"rclistfromreset": "Atiestatīt datuma izvēli",
"viewsourceold": "察源碼",
"editlink": "纂",
"viewsourcelink": "察源碼",
- "editsectionhint": "纂段:$1",
+ "editsectionhint": "所纂章名:$1",
"toc": "章",
"showtoc": "示",
"hidetoc": "藏",
"searchrelated": "關",
"searchall": "全",
"showingresults": "見'''$1'''尋,自'''$2'''始:",
- "search-nonefound": "詢中無結。",
+ "search-nonefound": "無所獲。",
"powersearch-legend": "尋",
"powersearch-ns": "尋名集:",
"powersearch-togglelabel": "核:",
"newpageletter": "新",
"boteditletter": "僕",
"number_of_watching_users_pageview": "[放有$1哨]",
- "rc-change-size-new": "既纂,本文有$1字節",
+ "rc-change-size-new": "纂後有$1字節",
"newsectionsummary": "/* $1 */ 新節",
"rc-enhanced-expand": "示細",
"rc-enhanced-hide": "藏細",
"VoteITP",
"아라",
"Macofe",
- "Fitoschido"
+ "Fitoschido",
+ "Baloch Khan"
]
},
"tog-underline": "Garih bawahi tautan:",
"october-date": "$1 Oktober",
"november-date": "$1 Nopember",
"december-date": "$1 Desember",
+ "period-am": "سهار",
+ "period-pm": "ماښام",
"pagecategories": "{{PLURAL:$1|Kategori}}",
"category_header": "Laman pado kategori \"$1\"",
"subcategories": "Subkategori",
"nospecialpagetext": "<strong>Sanak mamintak laman istimewa nan indak sah.</strong>\n\nDaftar laman istimewa nan sah dapek dicaliak di [[Special:SpecialPages|{{int:specialpages}}]].",
"error": "Kasalahan",
"databaseerror": "Kasalahan basis data",
+ "databaseerror-error": "تېروتنه: $1",
"laggedslavemode": "Paringatan: Laman mungkin indak barisi parubahan tabaru.",
"readonly": "Basis data dikunci",
"enterlockreason": "Masuakkan alasan panguncian, tamasuak pakiraan bilo kunci akan dibuka",
"createacct-reason": "Alasan",
"createacct-reason-ph": "Manga Sanak mambuek akun lain",
"createacct-submit": "Buek akun Sanak",
+ "createacct-another-submit": "ګڼون جوړول",
"createacct-benefit-heading": "{{SITENAME}} dibuek dek urang-urang saroman Sanak.",
"createacct-benefit-body1": "{{PLURAL:$1|suntiangan}}",
"createacct-benefit-body2": "{{PLURAL:$1|laman}}",
"download": "преземи",
"unwatchedpages": "Ненабљудувани страници",
"listredirects": "Список на пренасочувања",
- "listduplicatedfiles": "СпиÑ\81ок на подаÑ\82оÑ\82еки Ñ\81о дÑ\83пликаÑ\82и",
+ "listduplicatedfiles": "СпиÑ\81ок на дÑ\83плиÑ\80ани подаÑ\82оÑ\82еки",
"listduplicatedfiles-summary": "Ова е список на податотеки чија најнова верзија е дупликат на најнова верзија на некоја друга податотека. Се земаат предвид само месни податотеки.",
"listduplicatedfiles-entry": "[[:File:$1|$1]] има [[$3|{{PLURAL:$2|дупликат|$2 дупликати}}]].",
"unusedtemplates": "Неискористени шаблони",
"version-libraries-license": "Лиценца",
"version-libraries-description": "Опис",
"version-libraries-authors": "Автори",
- "redirect": "Ð\9fÑ\80енаÑ\81оÑ\87Ñ\83ваÑ\9aе по подаÑ\82оÑ\82ека, Ñ\81Ñ\82Ñ\80аниÑ\86а, пÑ\80еÑ\80абоÑ\82ка или назнака во дневникоÑ\82",
+ "redirect": "Ð\9fÑ\80енаÑ\81оÑ\87Ñ\83ваÑ\9aе по назнака на подаÑ\82оÑ\82ека, коÑ\80иÑ\81ник, Ñ\81Ñ\82Ñ\80аниÑ\86а, пÑ\80еÑ\80абоÑ\82ка или дневник",
"redirect-summary": "Оваа службена страница пренасочува кон податотека (се задава името), страница (се задава назнаката на преработката или страницата), корисничка странца (се задава бројчената назнака на корисникот) или дневнички запис (се дава назнака на записот). Употреба: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]] или [[{{#Special:Redirect}}/logid/186]].",
"redirect-submit": "Дај",
"redirect-lookup": "Пребарај:",
"changeemail-no-info": "ഈ താൾ നേരിട്ടു കാണുന്നതിന് താങ്കൾ ലോഗിൻ ചെയ്തിരിക്കണം.",
"changeemail-oldemail": "ഇപ്പോഴത്തെ ഇമെയിൽ വിലാസം:",
"changeemail-newemail": "പുതിയ ഇമെയിൽ വിലാസം:",
- "changeemail-newemail-help": "താà´\99àµ\8dà´\95ൾ à´\87à´®àµ\86യിൽ വിലാസà´\82 à´¨àµ\80à´\95àµ\8dà´\95à´\82à´\9aàµ\86à´¯àµ\8dയാനാà´\97àµ\8dരഹിà´\95àµ\8dà´\95àµ\81à´¨àµ\8dà´¨àµ\81à´µàµ\86à´\99àµ\8dà´\95ിൽ à´\88 മണàµ\8dà´¡à´²à´\82 à´\92à´´à´¿à´\9aàµ\8dà´\9aà´¿à´\9fàµ\81à´\95. à´\87à´®àµ\86യിൽ വിലാസà´\82 à´¨àµ\80à´\95àµ\8dà´\95à´\82à´\9aàµ\86à´¯àµ\8dതാൽ പിനàµ\8dà´¨àµ\86 മറനàµ\8dà´¨àµ\8d à´ªàµ\8bà´¯ രഹസàµ\8dയവാà´\95àµ\8dà´\95àµ\8d à´ªàµ\81à´¨à´\83à´¸à´\9càµ\8dà´\9càµ\80à´\95à´°à´¿à´\95àµ\8dà´\95ാനàµ\8b à´\88 വിà´\95àµ\8dà´\95ിയിൽ നിനàµ\8dà´¨àµ\81à´³àµ\8dà´³ à´\87à´®àµ\86യിലàµ\81à´\95ൾ à´¸àµ\8dà´µàµ\80à´\95à´°à´¿à´\95àµ\8dà´\95ാനàµ\8b à´\95ഴിയില്ല.",
+ "changeemail-newemail-help": "താà´\99àµ\8dà´\95ൾ à´\87à´®àµ\86യിൽ വിലാസà´\82 à´¨àµ\80à´\95àµ\8dà´\95à´\82à´\9aàµ\86à´¯àµ\8dയാൻ à´\86à´\97àµ\8dരഹിà´\95àµ\8dà´\95àµ\81à´¨àµ\8dà´¨àµ\81à´µàµ\86à´\99àµ\8dà´\95ിൽ à´\88 മണàµ\8dà´¡à´²à´\82 à´\92à´´à´¿à´\9aàµ\8dà´\9aà´¿à´\9fàµ\81à´\95. à´\87à´®àµ\86യിൽ വിലാസà´\82 à´¨àµ\80à´\95àµ\8dà´\95à´\82à´\9aàµ\86à´¯àµ\8dതാൽ പിനàµ\8dà´¨àµ\86 മറനàµ\8dà´¨àµ\8d à´ªàµ\8bà´¯ രഹസàµ\8dയവാà´\95àµ\8dà´\95àµ\8d à´ªàµ\81à´¨à´\83à´¸à´\9càµ\8dà´\9càµ\80à´\95à´°à´¿à´\95àµ\8dà´\95ാനàµ\8b à´\88 വിà´\95àµ\8dà´\95ിയിൽ നിനàµ\8dà´¨àµ\81à´³àµ\8dà´³ à´\87à´®àµ\86യിലàµ\81à´\95ൾ à´¸àµ\8dà´µàµ\80à´\95à´°à´¿à´\95àµ\8dà´\95ാനàµ\8b à´\95à´´à´¿à´¯àµ\81à´¨àµ\8dനതല്ല.",
"changeemail-none": "(ഒന്നുമില്ല)",
"changeemail-password": "താങ്കളുടെ {{SITENAME}} രഹസ്യവാക്ക്:",
"changeemail-submit": "ഇമെയിലിൽ മാറ്റംവരുത്തുക",
"recentchanges-legend": "സമീപകാല മാറ്റങ്ങളുടെ ക്രമീകരണം",
"recentchanges-summary": "{{SITENAME}} സംരംഭത്തിലെ ഏറ്റവും പുതിയ മാറ്റങ്ങൾ ഇവിടെ കാണാം.",
"recentchanges-noresult": "തന്നിരിക്കുന്ന സമയത്തിനുള്ളിൽ ഇതുമായി പൊരുത്തപ്പെടുന്ന മാറ്റങ്ങൾ ഒന്നുമില്ല.",
+ "recentchanges-timeout": "ഈ തിരച്ചിലിന്റെ സമയം അവസാനിച്ചു. വ്യത്യസ്ത ചരങ്ങൾ ഉപയോഗിച്ച് പരീക്ഷിക്കാവുന്നതാണ്.",
+ "recentchanges-network": "ഒരു സാങ്കേതിക പിഴവുണ്ടായതിനാൽ, ഫലങ്ങളൊന്നും എടുക്കാൻ കഴിഞ്ഞില്ല. ദയവായി താൾ റിഫ്രഷ് ചെയ്ത് നോക്കുക.",
+ "recentchanges-notargetpage": "ഒരു താളുമായി ബന്ധപ്പെട്ട മാറ്റങ്ങൾ കാണുവാൻ താളിന്റെ പേര് നൽകുക.",
"recentchanges-feed-description": "ഈ ഫീഡ് ഉപയോഗിച്ച് വിക്കിയിലെ പുതിയ മാറ്റങ്ങൾ നിരീക്ഷിക്കുക.",
"recentchanges-label-newpage": "ഒരു പുതിയ താൾ സൃഷ്ടിച്ചിരിക്കുന്നു",
"recentchanges-label-minor": "ഇതൊരു ചെറിയ തിരുത്താണ്",
"recentchangeslinked-feed": "അനുബന്ധ മാറ്റങ്ങൾ",
"recentchangeslinked-toolbox": "അനുബന്ധ മാറ്റങ്ങൾ",
"recentchangeslinked-title": "$1 എന്ന താളുമായി ബന്ധപ്പെട്ട മാറ്റങ്ങൾ",
- "recentchangeslinked-summary": "ഒരു പ്രത്യേക താളിൽ നിന്നു കണ്ണി ചേർക്കപ്പെട്ടിട്ടുള്ള താളുകളിൽ അവസാനമായി വരുത്തിയ മാറ്റങ്ങളുടെ പട്ടിക താഴെ പ്രദർശിപ്പിച്ചിരിക്കുന്നു. ഈ പട്ടികയിൽ പെടുന്ന [[Special:Watchlist|താങ്കൾ ശ്രദ്ധിക്കുന്ന താളുകൾ]] '''കടുപ്പിച്ച്''' കാണിച്ചിരിക്കുന്നു.",
+ "recentchangeslinked-summary": "ഒരു പ്രത്യേക താളിൽ നിന്നു കണ്ണി ചേർക്കപ്പെട്ടിട്ടുള്ള താളുകളിൽ അവസാനമായി വരുത്തിയ മാറ്റങ്ങളുടെ പട്ടിക താഴെ പ്രദർശിപ്പിച്ചിരിക്കുന്നു. (ഒരു വർഗ്ഗത്തിലെ താളുകൾ കാണാൻ {{ns:category}}:വർഗ്ഗത്തിന്റെ പേര് എന്ന് നൽകുക) ഈ പട്ടികയിൽ പെടുന്ന [[Special:Watchlist|താങ്കൾ ശ്രദ്ധിക്കുന്ന താളുകൾ]] '''കടുപ്പിച്ച്''' കാണിച്ചിരിക്കുന്നു.",
"recentchangeslinked-page": "താളിന്റെ പേര്:",
"recentchangeslinked-to": "തന്നിരിക്കുന്ന താളിലെ മാറ്റങ്ങൾക്കു പകരം ബന്ധപ്പെട്ട താളുകളിലെ മാറ്റങ്ങൾ കാണിക്കുക",
"recentchanges-page-added-to-category": "[[:$1]] വർഗ്ഗത്തിലേക്ക് ചേർത്തിരിക്കുന്നു",
"uploadstash-refresh": "പ്രമാണങ്ങളുടെ പട്ടിക പുതുക്കുക",
"uploadstash-thumbnail": "ലഘുചിത്രം കാണുക",
"uploadstash-bad-path-unknown-type": "അപരിചിതമായ തരം \"$1\".",
+ "uploadstash-file-not-found-no-thumb": "ലഘുചിത്രം സംഘടിപ്പിക്കാൻ കഴിഞ്ഞില്ല.",
+ "uploadstash-file-not-found-no-remote-thumb": "ലഘുചിത്രം എടുക്കൽ പരാജയപ്പെട്ടു: $1\nയു.ആർ.എൽ.= $2",
"img-auth-accessdenied": "പ്രവേശനമില്ല",
"img-auth-nopathinfo": "PATH_INFO ലഭ്യമല്ല.\nതാങ്കളുടെ സെർവർ ഈ വിവരം കൈമാറ്റം ചെയ്യാൻ തയ്യാറാക്കിയിട്ടില്ല.\nഅത് img_auth പിന്തുണയില്ലാത്ത സി.ജി.ഐ. അധിഷ്ഠിതമായ ഒന്നായിരിക്കാം.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization കാണുക.",
"img-auth-notindir": "ആവശ്യപ്പെട്ട പാത അപ്ലോഡ് ഡയറക്റ്ററിയിൽ സജ്ജീകരിച്ചു നൽകിയിട്ടില്ല.",
"filedelete-edit-reasonlist": "മായ്ക്കലിന്റെ കാരണം തിരുത്തുക",
"filedelete-maintenance": "നന്നാക്കൽ പ്രവർത്തനങ്ങൾ പുരോഗമിക്കുന്നതിനാൽ പ്രമാണങ്ങളുടെ മായ്ക്കലും പുനഃസ്ഥാപിക്കലും താത്ക്കാലികമായി നിർത്തിവച്ചിരിക്കുന്നു.",
"filedelete-maintenance-title": "പ്രമാണം മായ്ക്കാൻ കഴിയില്ല",
- "mimesearch": "മൈം(MIME) തിരയൽ",
- "mimesearch-summary": "ഈ താൾ പ്രമാണങ്ങളെ അവയുടെ മൈം(MIME)-തരം അനുസരിച്ച് അരിച്ചെടുക്കാൻ പ്രാപ്തമാക്കുന്നു:\nനൽകേണ്ടവിധം: പ്രമാണത്തിന്റെ തരം/ഉപതരം അല്ലെങ്കിൽ പ്രമാണത്തിന്റെ തരം/*, ഉദാ:<code>image/jpeg</code>.",
- "mimetype": "മൈം(MIME) തരം:",
+ "mimesearch": "മൈം (MIME) തിരയൽ",
+ "mimesearch-summary": "ഈ താൾ പ്രമാണങ്ങളെ അവയുടെ മൈം (MIME)-തരം അനുസരിച്ച് അരിച്ചെടുക്കാൻ പ്രാപ്തമാക്കുന്നു:\nനൽകേണ്ടവിധം: പ്രമാണത്തിന്റെ തരം/ഉപതരം അല്ലെങ്കിൽ പ്രമാണത്തിന്റെ തരം/*, ഉദാ:<code>image/jpeg</code>.",
+ "mimetype": "മൈം (MIME) തരം:",
"download": "ഡൗൺലോഡ്",
"unwatchedpages": "ആരും ശ്രദ്ധിക്കാത്ത താളുകൾ",
"listredirects": "തിരിച്ചുവിടൽ താളുകളുടെ പട്ടിക കാണിക്കുക",
"apisandbox-dynamic-parameters": "കൂടുതലായുള്ള ചരങ്ങൾ",
"apisandbox-dynamic-parameters-add-label": "ചരം ചേർക്കുക:",
"apisandbox-dynamic-parameters-add-placeholder": "ചരത്തിന്റെ പേര്",
+ "apisandbox-add-multi": "കൂട്ടിച്ചേർക്കുക",
+ "apisandbox-submit-invalid-fields-title": "ചില മണ്ഡലങ്ങൾ അസാധുവാണ്",
"apisandbox-results": "ഫലങ്ങൾ",
"apisandbox-request-url-label": "അഭ്യർത്ഥനാ യൂ.ആർ.എൽ.:",
"apisandbox-request-time": "അഭ്യർത്ഥനയുടെ സമയം: {{PLURAL:$1|$1 മി.സെ.}}",
"confirmemail_body_set": "$1 എന്ന ഐ.പി. വിലാസത്തിൽ നിന്നും ആരോ ഒരാൾ, മിക്കവാറും താങ്കളായിരിക്കും,\n{{SITENAME}} സംരംഭത്തിലെ \"$2\" എന്ന അംഗത്വത്തിന്റെ ഇമെയിൽ വിലാസമായി ഈ വിലാസം നൽകിയിരിക്കുന്നു.\n\n{{SITENAME}} സംരംഭത്തിലെ ഈ അംഗത്വം താങ്കളുടെ തന്നെയാണെന്ന് ഉറപ്പാക്കാനും, \nഇമെയിൽ സൗകര്യങ്ങൾ സജ്ജമാക്കാനും ഈ കണ്ണി ബ്രൗസറിൽ തുറക്കുക:\n\n$3\n\nഈ അംഗത്വം താങ്കളുടേത് *അല്ല* എങ്കിൽ\nഇമെയിൽ വിലാസ സ്ഥിരീകരണം റദ്ദാക്കാൻ താഴെക്കൊടുത്തിരിക്കുന്ന കണ്ണി ഉപയോഗിക്കുക:\n\n$5\n\nഈ സ്ഥിരീകരണ കോഡ് $4-നു കാലഹരണപ്പെടുന്നതാണ്.",
"confirmemail_invalidated": "ഇ-മെയിൽ വിലാസത്തിന്റെ സ്ഥിരീകരണം റദ്ദാക്കിയിരിക്കുന്നു",
"invalidateemail": "ഇ-മെയിൽ വിലാസ സ്ഥിരീകരണം റദ്ദാക്കുക",
+ "notificationemail_subject_changed": "{{SITENAME}} സംരംഭത്തിൽ രജിസ്റ്റർ ചെയ്ത ഇമെയിൽ വിലാസം മാറിയിരിക്കുന്നു",
+ "notificationemail_subject_removed": "{{SITENAME}} സംരംഭത്തിൽ രജിസ്റ്റർ ചെയ്ത ഇമെയിൽ വിലാസം നീക്കംചെയ്തിരിക്കുന്നു",
+ "notificationemail_body_changed": "$1 ഐ.പി. വിലാസത്തിൽ നിന്ന് ആരോ ഒരാൾ, മിക്കവാറും താങ്കളായിരിക്കാം,\n{{SITENAME}} സംരംഭത്തിലെ \"$2\" എന്ന അംഗത്വത്തിന്റെ ഇമെയിൽ വിലാസം \"$3\" എന്നാക്കി മാറ്റിയിരിക്കുന്നു.\n\nഇത് താങ്കൾ അല്ലെങ്കിൽ, സൈറ്റിന്റെ അഡ്മിനിസ്ട്രേറ്ററെ അടിയന്തരമായി ബന്ധപ്പെടുക.",
+ "notificationemail_body_removed": "$1 ഐ.പി. വിലാസത്തിൽ നിന്ന് ആരോ ഒരാൾ, മിക്കവാറും താങ്കളായിരിക്കാം,\n{{SITENAME}} സംരംഭത്തിലെ \"$2\" എന്ന അംഗത്വത്തിന്റെ ഇമെയിൽ വിലാസം നീക്കം ചെയ്തിരിക്കുന്നു.\n\nഇത് താങ്കൾ അല്ലെങ്കിൽ, സൈറ്റിന്റെ അഡ്മിനിസ്ട്രേറ്ററെ അടിയന്തരമായി ബന്ധപ്പെടുക.",
"scarytranscludedisabled": "[അന്തർവിക്കി ഉൾപ്പെടുത്തൽ സജ്ജമല്ല]",
"scarytranscludefailed": "[$1-നു ഫലകം കണ്ടുപിടിക്കാൻ പറ്റിയില്ല]",
"scarytranscludefailed-httpstatus": "[$1-നു ഫലകം എടുക്കാൻ കഴിഞ്ഞില്ല: എച്ച്.റ്റി.റ്റി.പി. $2]",
"fileduplicatesearch-noresults": "\"$1\" എന്ന പേരിൽ ഒരു പ്രമാണവും കണ്ടെത്താനായില്ല.",
"specialpages": "പ്രത്യേക താളുകൾ",
"specialpages-note-top": "സൂചന",
+ "specialpages-note-restricted": "* പൊതുവേ ഉപയോഗിക്കുന്ന പ്രത്യേക താളുകൾ.\n* <span class=\"mw-specialpagerestricted\">ഉപയോഗം പരിമിതപ്പെടുത്തിയിരിക്കുന്ന പ്രത്യേക താളുകൾ.</span>",
"specialpages-group-maintenance": "പരിചരണം ആവശ്യമായവ",
"specialpages-group-other": "മറ്റു പ്രത്യേക താളുകൾ",
"specialpages-group-login": "പ്രവേശിക്കുക / അംഗത്വമെടുക്കുക",
"cannotauth-not-allowed-title": "അനുമതി നിഷേധിച്ചിരിക്കുന്നു",
"cannotauth-not-allowed": "ഈ താൾ ഉപയോഗിക്കാൻ താങ്കൾക്ക് അനുവാദമില്ല",
"credentialsform-account": "അംഗത്വ നാമം:",
+ "cannotlink-no-provider-title": "കണ്ണി ചേർക്കാവുന്ന അംഗത്വങ്ങൾ ഒന്നുമില്ല",
+ "cannotlink-no-provider": "കണ്ണി ചേർക്കാവുന്ന അംഗത്വങ്ങൾ ഒന്നുമില്ല",
+ "linkaccounts": "അംഗത്വങ്ങൾ കണ്ണി ചേർക്കുക",
+ "linkaccounts-success-text": "അംഗത്വം കണ്ണി ചേർത്തു.",
+ "linkaccounts-submit": "അംഗത്വങ്ങൾ കണ്ണി ചേർക്കുക",
+ "unlinkaccounts": "അംഗത്വങ്ങൾ കണ്ണി മാറ്റുക",
+ "unlinkaccounts-success": "അംഗത്വം കണ്ണി മാറ്റി.",
"restrictionsfield-badip": "അസാധുവായ ഐ.പി. വിലാസം അല്ലെങ്കിൽ പരിധി:$1",
"restrictionsfield-label": "അനുവദിച്ചിട്ടുള്ള ഐ.പി. പരിധികൾ:",
"edit-error-short": "പിഴവ്: $1",
"tog-usenewrc": "Molōloāzqueh in tlapatlaliztli in yancuīc tlapatlaliztli āmapan īhuān in tlachiyaliztli tlapōhualāmapan (monequi JavaScript)",
"tog-showtoolbar": "Motlaīxtlatīz in tlachihchīhualōni pāntli",
"tog-editondblclick": "Tiquimpatlāz in zāzanilli intlā ōme tiquimpachoa",
- "tog-watchcreations": "Moaquiāz in āmatl mā niquinyōcoya īhuān in tlahcuilōlli mā niquinquetza īpan notlachiyaliz",
+ "tog-watchcreations": "Niquintlaliz in tlahcuilolamameh in oniquinchiuh ihuan in tlahcuilolpiyaliztin in oniquinquetz ipan notlachiyaliz",
"tog-watchdefault": "Moaquiāz āmatl īhuān tlahcuilōlli mā niquinpatla in notlachiyaliz",
"tog-watchmoves": "Moaquiāz āmatl īhuān tlahcuilōlli mā niquinzaca in notlachiyaliz",
- "tog-watchdeletion": "Moaquiāz āmatl īhuān tlahcuilōlli mā niquimpolo in notlachiyaliz",
+ "tog-watchdeletion": "Niquintlaliz tlahcuilolamameh ihuan tlahcuilolpiyaliztin in oniquimpoloh ipan notlachiyaliz",
"tog-minordefault": "Ticmachiyōtīz mochīntīn tlapatlalitzintli ic default",
"tog-previewontop": "Tiquittāz achtochīhualiztli achtopa tlapatlaliztli caxitl",
"tog-previewonfirst": "Xiquitta achtochīhualiztli inic cē tlapatlalizpan",
"tog-enotifminoredits": "Notech moēhualtia cē maltzinteyōtl netitlaniztli nō ihcuāc mopatla tepitōn zāzanilli in notlachiyaliz.",
"tog-enotifrevealaddr": "Ticnēxtīz mo e-mailcān āxcāncayōtechcopa āmatlacuilizpan",
"tog-shownumberswatching": "Tiquinttāz tlatequitiltilīlli tlein tlachiyacateh",
- "tog-oldsig": "Nicān tōcāyoh:",
+ "tog-oldsig": "Iuh otictlalih motoca:",
"tog-fancysig": "Wikitext īpan ticmatiz tōcāyoh (in ahtleh auto-link)",
"tog-forceeditsummary": "Xinēchnōtzāz ihcuāc ahmo niquihtōz inōn ōnitlapatlac",
"tog-watchlisthideown": "Tictlatiz mopatlaliz ipan motlachiyaliz",
"tog-diffonly": "Ahmo tiquittāz zāzanilli ītlapiyaliz ahneneuhquilitzīntlan",
"tog-showhiddencats": "Mà monèxtìkàn in tlatlatìltìn tlaìxmatkàtlàlilòmë",
"underline-always": "Mochipa",
- "underline-never": "Aīc",
+ "underline-never": "Aic",
"editfont-monospace": "Cencoyahualiztli machiyotlahtoliztli",
"editfont-sansserif": "Sans-serif machiyotlahtoliztli",
"editfont-serif": "Serif machiyotlahtoliztli",
"november": "11 Metz",
"december": "12 Metz",
"january-gen": "Ic cē mētztli",
- "february-gen": "Īcōmemētztli",
+ "february-gen": "Icomemetztli",
"march-gen": "Īcyēyimētztli",
"april-gen": "Ic nauhtetl metztli",
"may-gen": "Īcmācuīllimētztli",
"article": "Tlahcuilolamatl",
"newwindow": "(Motlapoaz ce yancuic tlanexillotl)",
"cancel": "Moxitiniz",
- "moredotdotdot": "Huehca ōmpa...",
- "mypage": "Noāmauh",
+ "moredotdotdot": "Ocachi...",
+ "mypage": "Notlahcuilolamauh",
"mytalk": "Teixnamiquiliztli",
"anontalk": "Teixnamiquiliztli",
"navigation": "Panoliztli",
"namespaces": "Tocatlacauhtli",
"variants": "Nepapan",
"navigation-heading": "Nemiliztlahtolpohualamatl",
- "errorpagetitle": "Aiuhcāyōtl",
+ "errorpagetitle": "Ahiuhcayotl",
"returnto": "Ximocuepa ihuic $1.",
"tagline": "Itechcopa {{SITENAME}}",
"help": "Tepalehuiliztli",
"newpage": "Yancuic tlahcuilolli",
"talkpagelinktext": "Teixnamiquiliztli",
"specialpage": "Noncuahquizcatlahcuilolamatl",
- "personaltools": "In tlein nitēquitiltilia",
+ "personaltools": "Motequitihuilocahuan",
"talk": "Teixnamiquiliztli",
"views": "Tlachiyaliztli",
"toolbox": "Tequitihualoni",
"imagepage": "Tiquittaz in tlahcuilolamatl itecpanaliztlapiyaliz",
"mediawikipage": "Xiquitta tetitlaniliztli itlahcuilolamauh",
"templatepage": "Xiquitta tlahcuilolamatl ineixcuitil",
- "viewhelppage": "Xiquitta tēpalēhuiliztli zāzanilli",
+ "viewhelppage": "Xiquitta in tepalehuiliztli itlahcuilolamauh",
"categorypage": "Tiquittaz neneuhcayotl itlahcuilolamauh",
- "viewtalkpage": "Xiquitta tēixnāmiquiliztli zāzanilli",
- "otherlanguages": "Occequintin tlahtlahtolcopa",
- "redirectedfrom": "(Ōmotlacuep īhuīcpa $1)",
- "redirectpagesub": "Ōmotlacuep zāzanilli",
- "lastmodifiedat": "Inin tlahcuilolli omopatlac immanin $1, ipan $2.",
+ "viewtalkpage": "Xiquitta in teixnamiquiliztli",
+ "otherlanguages": "Occequi tlahtolli",
+ "redirectedfrom": "(Omocuep ihuicpa $1)",
+ "redirectpagesub": "Tlacueptli itlahcuilolamauh",
+ "lastmodifiedat": "Inin tlahcuilolamatl omopatlac immanin $1, ipan $2.",
"viewcount": "Inīn zāzanilli quintlapōhua {{PLURAL:$1|cē tlahpololiztli|$1 tlahpololiztli}}.",
- "protectedpage": "Ōmoquīxtix zāzanilli",
- "jumpto": "Īhuīcpa ticholōz:",
+ "protectedpage": "Tlamaquixtilli tlahcuilolamatl",
+ "jumpto": "Ticholoz ihuicpa:",
"jumptonavigation": "amapanoliztli",
"jumptosearch": "Tlatemoliztli",
"aboutsite": "Itechcopa {{SITENAME}}",
"currentevents-url": "Project:Axcancayotl",
"disclaimers": "tlamamalquixtiliztli",
"edithelp": "Tepalehuiliztli ica tlapatlaliztli",
- "helppage-top-gethelp": "Tēpalēhuiliztli",
+ "helppage-top-gethelp": "Tepalehuiliztli",
"mainpage": "Yacatlahcuilolli",
"mainpage-description": "Yacatlahcuilolli",
"policy-url": "Project:Nahuatīltōn",
- "portal": "Yacatlahcuilolli tocalpol",
- "portal-url": "Project:Yacatlahcuilolli tocalpol",
+ "portal": "Necentlaliloyan",
+ "portal-url": "Project:Necentlaliloyan",
"privacy": "Tlahcuilolli piyaliznahuatilli",
"privacypage": "Project:Tlahcuilōlpiyaliztechcopa nahuatīltōn",
"badaccess": "Tlahuelītiliztechcopa ahcuallōtl",
"badaccess-group0": "Tehhuatl ahmo hueli ticchihua in tlein tiquelehuia.",
"badaccess-groups": "Inin tlen tiquelehuia zan quichihuah tequitiuhqueh {{PLURAL:$2|itech necentlaliliztli| centetl itech inin $2 necentlaliliztin}}: $1.",
"ok": "Cayecualli",
- "retrievedfrom": "Ōquīzqui ītech \"$1\"",
+ "retrievedfrom": "Oquiz itech \"$1\"",
"youhavenewmessages": "Tiquimpiya $1 ($2).",
"youhavenewmessagesmulti": "Tiquimpiya yancuīc tlahcuilōlli īpan $1",
"editsection": "Ticpatlaz",
"toc": "In tlein quipiya inin tlahcuilolli",
"showtoc": "xicnēxti",
"hidetoc": "xictlāti",
- "collapsible-collapse": "Motlàtìs",
- "collapsible-expand": "Monèxtìs",
- "confirmable-yes": "Quēmah",
- "confirmable-no": "Ahmō",
- "thisisdeleted": "¿Tiquittaz nozo ahticpolōz $1?",
- "viewdeleted": "¿Tiquiēlēhuia tiquitta $1?",
- "restorelink": "{{PLURAL:$1|cē tlapatlaliztli polotic|$1 tlapatlaliztli polotic}}",
- "feedlinks": "Olōlpōl:",
+ "collapsible-collapse": "Motlatiz",
+ "collapsible-expand": "Monextiz",
+ "confirmable-yes": "Quemah",
+ "confirmable-no": "Ahmo",
+ "thisisdeleted": "¿Tiquittaz nozo ahticpoloz $1?",
+ "viewdeleted": "¿Cuix tiquittaznequi $1?",
+ "restorelink": "{{PLURAL:$1|cē tlapatlaliztli mopoloh|$1 tlapatlaliztin mopolohqueh}}",
+ "feedlinks": "Nemaccayotl:",
"site-rss-feed": "$1 RSS huelītiliztli",
- "site-atom-feed": "$1 Atom huelītiliztli",
+ "site-atom-feed": "Atom tlamantli itech $1",
"page-rss-feed": "\"$1\" RSS huelītiliztli",
"page-atom-feed": "\"$1\" RSS huelitiliztli",
"red-link-title": "$1 (ahmo oncah tlahcuilolamatl)",
"nosuchaction": "Ahmo ia tlachīhualiztli",
"nosuchspecialpage": "Âmò ka inòn nònkuâkìskàtlaìxtlapalli",
"nospecialpagetext": "<strong>Tiknẻki sè nònkuâkìskàtlaìxtlapalli tlèn âmò kä.</strong>\n\nKualli tikỉtas sè ìntlapòpòwaltekpànal in nònkuâkìskàtlaìxtlapaltìn ìpan [[Special:SpecialPages|{{int:specialpages}}]].",
- "error": "Ahcuallōtl",
+ "error": "Ahiuhcayotl",
"databaseerror": "Tlahcuilōltzintlān īahcuallo",
"databaseerror-query": "Tlahtlanilli: $1",
+ "databaseerror-error": "Ahiuhcayotl $1",
"laggedslavemode": "Xiquitta: huel ahmo ia achi yancuīc in tlapatlaliztli inīn zāzanilco.",
"readonly": "Mactzīntlantli tzahtzacticah",
"missingarticle-rev": "(tlachiyaliztli ītlapōhual: $1)",
"missingarticle-diff": "(Ahneneuh.: $1, $2)",
- "internalerror": "Ahcuallōtl tlahtic",
- "internalerror_info": "Ahcuallōtl tlahtic: $1",
+ "internalerror": "Ahiuhcayotl tlahtic",
+ "internalerror_info": "Ahiuhcayotl tlahtic: $1",
"filecopyerror": "Ahmō ōmohuelītic tlacopīna \"$1\" īhuīc \"$2\".",
"filerenameerror": "Ahmō ōmohuelītic tlazaca \"$1\" īhuīc \"$2\".",
"filedeleteerror": "Ahmō ōmohuelītic tlapoloa \"$1\".",
"userlogout": "Xiquīza",
"notloggedin": "Ahmō ōtimocalac",
"userlogin-noaccount": "Cuix ahmo titlapohualeh?",
- "createaccount": "Xicchīhua tlapōhualli",
+ "createaccount": "Xicchihua ce tlapohualli",
"createacct-email-ph": "xiquihcuilo mocorreo electrónico",
"createaccountmail": "Ticnemītīz ahmo cemihcac zāzoichtacātlahtōlli nō in tiquēhualtīz in maltzinteyōtl monetitlanizyeyān",
"createacct-reason": "Tleīpampa",
"retypenew": "Occeppa xiquihcuiloa yancuīc motlahtōlichtacayo:",
"resetpass_submit": "Xicpatlāz motlahtōlichtacāyo auh xicalaquīz",
"changepassword-success": "Moichtacātlahtōl ōmopatlac.",
+ "botpasswords-label-cancel": "Moxitiniz",
"resetpass_forbidden": "Tlahtōlichtacayōtl ahmo mohuelītih mopatlah",
"resetpass-submit-loggedin": "Ticpatlāz motlahtōlichtacāyo",
- "resetpass-submit-cancel": "Xiccahua",
+ "resetpass-submit-cancel": "Moxitiniz",
"passwordreset-username": "Tequihuihcātōcāitl:",
- "bold_sample": "Tliltic tlahcuilolpiyaliz",
- "bold_tip": "Tlīltic tlahcuilōlli",
+ "bold_sample": "Tliltic tlahcuiloliztli",
+ "bold_tip": "Tliltic tlahcuiloliztli",
"italic_sample": "Nacacic tlahcuiloliztli",
"italic_tip": "Nacacic tlahcuiloliztli",
"link_sample": "Tzonhuiliztli ītōcā",
"templatesused": "{{PLURAL:$1|Nemachiotl tlen motequiuhtia|Nemachiomeh tlen moquintequiuhtiah}} ipan inin tlahcuilolamatl:",
"templatesusedpreview": "{{PLURAL:$1|Nemachiotl tlen motequiuhtia|Nemachiomeh tlen moquintequiuhtiah}} ipan inin achtochihualiztli:",
"templatesusedsection": "{{PLURAL:$1|Nemachiotl tlen motequiuhtia|Nemachiomeh tlen moquintequiuhtiah}} ipan inin tlaxeloliztli:",
- "template-protected": "(ōmoquīxti)",
+ "template-protected": "(ahmo moquixtia)",
"hiddencategories": "Inin tlahcuilolli pohui {{PLURAL:$1|1 tlatlalilli neneuhcayotl|$1 tlatlaliltin neneuhcayomeh}}:",
"nocreatetext": "Inin huiqui oquitzacuili ic mochihua yancuic tlahcuilolamatl. Quil ticcuepaznequi auh ticpatlaz occe tlahcuilolamatl, [[Special:UserLogin|xicalaqui nozo xicchihua ce cuentah]].",
"nocreate-loggedin": "Ahmo hueli ticchihua yancuic tlahcuilolamatl.",
"permissionserrors": "Tēmācāhualiztli aiuhcāyōtl",
"permissionserrorstext": "Ahmo tihuelīti quichīhua inōn, inīn {{PLURAL:$1|īxtlamatilizpampa}}:",
"permissionserrorstext-withaction": "Ahmo tiquihuelīti $2 inīn {{PLURAL:$1|īxtlamatilizpampa}}:",
- "moveddeleted-notice": "Inin tlahcuilolamatl omopoloh.\nIn tlapololiztli ihuan in tlazacaliztli tlahcuilolloh cah tlani.",
+ "moveddeleted-notice": "Inin tlahcuilolamatl omopoloh.\nIn tlapololiztli ihuan in tlazacaliztli itlahcuilolloh cah tlani.",
"edit-gone-missing": "Ahmo huelīti yancuīya zāzanilli.\nHueliz ōmopolo.",
"edit-conflict": "Tlapatlaliztli yāōyōtōn",
"edit-already-exists": "Ahmo mohuelīti mochīhua yancuīc zāzanilli.\nYe ia.",
"content-model-javascript": "JavaScript",
"cantcreateaccount-text": "[[User:$3|$3]] ōcquīxti cuentah tlachīhualiztli īpal inīn IP ('''$1''').\n\nĪxtlamatiliztli īpal $3 cah ''$2''",
- "viewpagelogs": "Tiquinttāz tlahcuilōlloh inīn zāzaniltechcopa",
+ "viewpagelogs": "Tiquittaz in tlahcuilolamatl itlahtollouh",
"nohistory": "Nicān ahmō oncah tlaīxtlapatlaliztlahtōllōtl.",
"currentrev": "Āxcān tlapatlaliztli",
"currentrev-asof": "Āxcān tlachiyaliztli īpan $1",
"last": "xocoyoc",
"page_first": "achto",
"page_last": "xōcoyōc",
- "history-fieldset-title": "Xitlatēmo īpan tlahtōllōtl",
+ "history-fieldset-title": "Xitlatemo ihtic tlahtollotl",
"history-show-deleted": "Zan tlapololtin",
"histfirst": "in achto",
"histlast": "in tlatzaucticah",
"historysize": "({{PLURAL:$1|1 byte|$1 byte}})",
- "historyempty": "(iztāc)",
+ "historyempty": "(cactic)",
"history-feed-title": "Tlaceppahuiliztlahtōllōtl",
"history-feed-description": "Tlachiyaliztli tlahcuilōlloh inīn zāzaniltechcopa huiquipan",
"history-feed-item-nocomment": "$1 īpan $2",
"mergehistory-comment": "Ōmocēntili [[:$1]] īpan [[:$2]]: $3",
"mergehistory-reason": "Tleīpampa:",
"revertmerge": "Ticahtletiliz in cetiliztli",
- "history-title": "«$1» ītlaceppahuiliztlahtōllo",
+ "history-title": "Nepapan tlahcuilollotl itechpa «$1»",
"lineno": "Pantli $1:",
"editundo": "Ticxitiniz",
"searchresults": "motlatemoliz itlananquilizhuan",
"searchprofile-articles": "Itech tlahcuilolamatl",
"searchprofile-images": "Nepapan media",
"searchprofile-everything": "Mochi",
- "searchprofile-advanced": "Huehca ōmpa",
- "searchprofile-articles-tooltip": "Tictēmōz īpan $1",
+ "searchprofile-advanced": "Quizqui",
+ "searchprofile-articles-tooltip": "Tictemoz ipan $1",
"searchprofile-images-tooltip": "motemoz tlapiyaliztecpaliztli",
- "searchprofile-everything-tooltip": "Tictēmōz mochi tlapiyalizpan (mopiyah tēixnāmiquiliztli zāzanilli)",
- "search-result-size": "$1 ({{PLURAL:$2|1 tlahtōl|$2 tlahtōltin}})",
+ "searchprofile-everything-tooltip": "Tictemoz ipan mochi tlapiyaliztli (noihuan tlahcuilolamatl iteixnamiquiliz)",
+ "search-result-size": "$1 ({{PLURAL:$2|1 tlahtol|$2 tlahtoltin}})",
"search-redirect": "(ixquichca ompa mitzhuica $1)",
"search-section": "(tlahtōltzintli $1)",
"search-category": "(neneuhcayotl $1)",
"search-suggest": "Ahnōceh tiquihtōznequiya: $1",
"search-interwiki-caption": "Tlachīhualiztli īcnīhuān",
- "search-interwiki-more": "(huehca ōmpa)",
+ "search-interwiki-more": "(ocachi)",
"search-relatedarticle": "Ītechcopa",
"searchrelated": "ītechcopa",
"searchall": "mochīntīn",
"group": "Necentlaliliztli:",
"group-user": "Tequihuihqueh",
"group-bot": "Tepoztlācah",
- "group-sysop": "Tlahcuilōlpixqueh",
+ "group-sysop": "Huiquipixqueh",
"group-all": "(mochīntīn)",
"group-user-member": "{{GENDER:$1|tlatequitiltilīlli}}",
"group-bot-member": "{{GENDER:$1|tepozcuāyōllōtl}}",
- "group-sysop-member": "{{GENDER:$1|tētlamahmacani}}",
+ "group-sysop-member": "{{GENDER:$1|huiquipixqui}}",
"grouppage-user": "{{ns:project}}:Tlatequitiltilīlli",
"grouppage-bot": "{{ns:project}}:Tepoztlācah",
- "grouppage-sysop": "{{ns:project}}:Tlahcuilōlpixqueh",
- "right-read": "Tiquimpōhuāz zāzaniltin",
- "right-edit": "Tiquimpatlāz zāzaniltin",
- "right-createpage": "Ticchīhuāz zāzaniltin (ahmo tēixnāmiquiliztli zāzaniltin)",
- "right-createtalk": "Ticchīhuāz tēixnāmiquiliztli zāzaniltin",
+ "grouppage-sysop": "{{ns:project}}:Huiquipixqueh",
+ "right-read": "Tiquimpohuaz tlahcuilolamameh",
+ "right-edit": "Tiquimpatlaz tlahcuilolamameh",
+ "right-createpage": "Ticchihuaz tlahcuilolamameh (ahmo teixnamiquiliztli tlahcuilolamatl)",
+ "right-createtalk": "Ticchihuaz teixnamiquiliztli itlahcuilolamauh",
"right-createaccount": "Ticchīhuaz yancuic tlapōhualli",
"right-minoredit": "Ticpatlāz quemeh tlapatlalitzintli",
"right-move": "Tiquinzacāz zāzaniltin",
"recentchanges": "Yancuic tlapatlaliztli",
"recentchanges-legend": "Yancuīc tlapatlaliztechcopa tlanequiliztli",
"recentchanges-summary": "Tictoquiliz itlapatlaliz oc yancuic inahuac huiqui inin tlahcuilolpan.",
- "recentchanges-label-newpage": "Inīn tlapatlaliztli ōquiyōcox cē yancuīc āmatl",
+ "recentchanges-label-newpage": "Inin tlapatlaliztli oquiyocox ce yancuic tlahcuilolamatl",
"recentchanges-label-minor": " Inin tepiton tlapatlaliztli",
"recentchanges-label-bot": "Inin tlapaltlaliztli oquichiuh ce robot",
+ "rcfilters-savedqueries-cancel-label": "Moxitiniz",
"rclistfrom": "Xiquittaz yancuic tlapatlaliztli ixquichca $3 ihuicpa $2",
"rcshowhideminor": "$1 tlapatlalitzintli",
"rcshowhideminor-show": "Xicnexti",
"sourceurl": "Mēyal-URL:",
"destfilename": "Tōcāhuīc:",
"watchthisupload": "Tictlachiyaz inin tecpanaliztlapiyaliztli",
+ "upload-dialog-button-cancel": "Moxitiniz",
"upload-form-label-infoform-name": "Tōcāitl",
"upload-form-label-usage-filename": "Ihcuilōlli ītōcā",
"upload_source_file": "(ticpepenaz ce tlahcuilolli mochiuhpohualhuazco)",
"listfiles-latestversion-yes": "Quēmah",
"listfiles-latestversion-no": "Ahmō",
"file-anchor-link": "Tlapiyaliztecpanaliztli",
- "filehist": "Ihcuilōlli ītlahtōllo",
+ "filehist": "Tlahcuilolli itlahtollo",
"filehist-deleteall": "tiquimpolōz mochīntīn",
"filehist-deleteone": "xicpolo",
"filehist-revert": "tlacuepāz",
"filedelete-edit-reasonlist": "Xiquihto ipampa ticpohpoloznequi in",
"mimesearch": "MIME tlatemoliztli",
"mimetype": "MIME iuhcāyōtl:",
- "download": "tictemōz",
+ "download": "tictemoz",
"unwatchedpages": "Zāzaniltin ahmo motlachiya",
"listredirects": "Tlacuepaliztli",
"unusedtemplates": "Nemachiyōtīlli ahmotequitiltiah",
"statistics-header-edits": "Tlapatlaliztli tlapōhualli",
"statistics-header-users": "Tlatequitiltilīlli ītlapōhualiz",
"statistics-articles": "Tlapiyaliztli zāzanilli",
- "statistics-pages": "Zāzaniltin",
+ "statistics-pages": "Tlahcuilolamameh",
"statistics-pages-desc": "Mochīntīn zāzaniltin huiquipan, mopiyah tēixnāmiquiliztli, tlacuepaliztli, etz.",
"statistics-files": "Tlahcuilōlli ōmoquetz",
"doubleredirects": "Ōntetl tlacuepaliztli",
"deadendpages": "Ahtlaquīzaliztli zāzaniltin",
"protectedpages": "Zāzaniltin ōmoquīxti",
"protectedpages-indef": "Zan ahcāhuitl tlaquīxtiliztli",
- "protectedpages-page": "Tlaīxtli",
+ "protectedpages-page": "Tlahcuilolamatl",
"protectedpages-reason": "Tleīpampa",
"protectedtitles": "Tōcāitl ōmoquīxtih",
"listusers": "Tlatequitiltilīlli",
"newpages": "Yancuic tlahcuiloltin",
"newpages-username": "Tlatequitiltilīltōcāitl:",
"ancientpages": "Huehcauh tlahcuilolamatl",
- "move": "Ticzacāz",
+ "move": "Ticzacaz",
"movethispage": "Ticzacāz inīn zāzanilli",
"pager-newer-n": "{{PLURAL:$1|1 yancuic|$1 yancuicqueh}}",
"pager-older-n": "{{PLURAL:$1|1 huehcauh|$1 huehcauhqueh}}",
"booksources-search-legend": "Tiquixtemoz amoxtli itzintiliz",
"booksources-search": "Tlatemoliztli",
"specialloguserlabel": "Tlatequitiltilīlli:",
- "speciallogtitlelabel": "Tōcāitl:",
+ "speciallogtitlelabel": "Ahciliztli (itoca nozo {{ns:user}}:tequitiuhqui itoca):",
"log": "Tlahcuilolloh",
"all-logs-page": "Mochintin nohuiyanyoh intlahcuilolhuan",
"allpages": "Mochintin tlahcuilolamatl",
"linksearch-line": "$1 tzonhuīlo īxquichca $2",
"listusers-submit": "Tiquittāz",
"activeusers-submit": "Xiquitta",
- "listgrouprights-group": "Olōlli",
+ "listgrouprights-group": "Necentlaliliztli",
"listgrouprights-rights": "Huelītiliztli",
"emailuser": "Tiquēhualtlīz maltzinteyōtl netitlaniztli inīn tlatequitiltilīlli",
"defemailsubject": "{{SITENAME}} correo tlatequitiltilīlhuīc $1",
"mywatchlist": "Notlachiyaliz",
"watchnologin": "Ahmo ōtimocalac",
"removedwatchtext": "Zāzanilli \"[[:$1]]\" ōmopolo [[Special:Watchlist|motlachiyalizco]].",
- "watch": "Tictlachiyāz",
+ "watch": "Titlachiyaz",
"watchthispage": "Tictlachiyāz inīn zāzanilli",
"unwatch": "Ahmo titlachiyaz",
- "watchlist-details": "{{PLURAL:$1|$1 zāzanilli|$1 zāzaniltin}} motlachiyaliz, ahmo mopōhua tēixnāmiquiliztli.",
- "wlshowlast": "Tiquinttāz tlapatlaliztli īhuīcpa achto $1 yēmpohualminuhtli, $2 tōnaltin",
+ "watchlist-details": "Oncah {{PLURAL:$1|$1 tlahcuilolamatl|$1 tlahcuilolamameh}} ipan motlachiyaliz (oc tlahcuilolamatl iteixnamiquiliz).",
+ "wlshowlast": "Tiquittaz itlapatlaliz itech $1 horas, $2 tonaltin",
"watching": "Tlachiyacah...",
"unwatching": "Ahtlachiyacah...",
"enotif_impersonal_salutation": "tlatequitiltilīlli īpan {{SITENAME}}",
"protect-expiry-options": "1 hora:1 hour,1 tonalli:1 day,1 chicueyilhuitl:1 week,2 chicueyilhuitl:2 weeks,1 metztli:1 month,3 metztli:3 months,6 metztli:6 months,1 xihuitl:1 year,mochipa:infinite",
"restriction-type": "Temacahualiztli:",
"restriction-edit": "xicpatla",
- "restriction-move": "Ticzacāz",
+ "restriction-move": "Ticzacaz",
"restriction-create": "Ticchīhuāz",
"restriction-upload": "Tlahcuilōlquetza",
"undelete": "Tiquimittaz tlahcuilolamameh tlen omopohpolohqueh",
"contributions": "In {{GENDER:$1|tlatequitiltilīlli}} ītlahcuilōl",
"contributions-title": "Tlatequitiltilīlli $1 ītlahcuilōl",
"mycontris": "Notlahcuilol",
- "contribsub2": "$1 ($2)",
+ "contribsub2": "Ihuicpa {{GENDER:$3|$1}} ($2)",
"uctop": "(axcan tlapatlaliztli)",
- "month": "Īhuīcpa mētztli (auh achtopa):",
- "year": "Xiuhhuīcpa (auh achtopa):",
+ "month": "Metzpan (auh yeppa):",
+ "year": "Xiuhpan (auh yeppa):",
"sp-contributions-newbies": "Tiquinttāz zan yancuīc tlatequitiltilīlli īntlapatlaliz",
"sp-contributions-newbies-sub": "Ic yancuīc",
"sp-contributions-newbies-title": "Yancuīc tlatequitiltilīlli ītlahcuilōl",
"whatlinkshere-page": "Tlahcuilolamatl:",
"linkshere": "Inīn zāzaniltin quitzonhuiliah '''[[:$1]]''' īhuīc:",
"nolinkshere": "Ahtle quitzonhuilia '''[[:$1]]''' īhuīc.",
- "isredirect": "ōmotlacuep zāzanilli",
+ "isredirect": "Tlacueptli tlahcuilolamatl",
"isimage": "īxiptlahtli tzonhuiliztli",
"whatlinkshere-prev": "{{PLURAL:$1|achtopa|$1 achtopa}}",
"whatlinkshere-next": "{{PLURAL:$1|niman|$1 niman}}",
"whatlinkshere-links": "← tzohuiliztin",
"whatlinkshere-hideredirs": "$1 tlacuepaliztli",
"whatlinkshere-hidelinks": "$1 tzonhuiliztli",
- "whatlinkshere-hideimages": "$1 tlahcuilōltzonhuīliztli",
+ "whatlinkshere-hideimages": "$1 tlahcuiloltzonhuiliztli",
"whatlinkshere-filters": "Tlatzetzelōni",
"blockip": "Tiquitzacuilīz tlatequitiltilīlli",
"ipaddressorusername": "IP nozo tlatequitiltilīlli ītōcā:",
"change-blocklink": "Ticpatlaz tlatzacualli",
"contribslink": "tlapatlaliztli",
"blocklogpage": "Tlatequitiltilīlli ōmotzacuili",
- "move-page": "Ticzacāz $1",
+ "move-page": "Ticzacaz $1",
"move-page-legend": "Tictocapatlaliz inin tlahcuilolamatl",
"movepagetext": "Nicān mohcuiloa quemeh ticzacāz cē zāzanilli auh mochi in ītlahcuillōloh īhuīc occē yancuīc ītōca.\nHuēhuehtōcāitl yez tlacuepaliztli yancuīc tōcāhuīc.\nTzonhuiliztli huēhuehzāzanilhuīc ahmo mopatlāz.\nXiquitta ic māca xicchīhua [[Special:DoubleRedirects|ōntlacuepaliztli]] ahnozo [[Special:BrokenRedirects|tzomoc]].\nTitzonhuilizpiyāz.\n\nXicmati in zāzanilli ahmo mozacāz intlā ye ia cē zāzanilli tōcātica, zan cah iztāc zāzanilli ahnozo tlacuepaliztli īca ahmo tlahcuilōlloh.\nQuihtōznequi tihuelītīz ticuepāz cē zāzanilli īhuīc ītlācatōca intlā ahcuallōtl ticchīhuāz, tēl ahmo tihuelītīz occeppa tihcuilōz īpan zāzanilli tlein ia.\n\n'''¡XICPŌHUA!'''\nHueliz cah inīn huēyi tlapatlaliztli. Timitztlātlauhtia ticmatīz cuallōtl auh ahcuallōtl achtopa ticzacāz.",
"movenotallowed": "Ahmo tihuelīti tiquinzaca zāzaniltin.",
"movelogpage": "Tlazacaliztli tlahcuilōlloh",
"movereason": "Īxtlamatiliztli:",
"revertmove": "tlacuepāz",
- "delete_and_move_confirm": "Quēmah, ticpolōz in zāzanilli",
- "immobile-source-namespace": "Ahmo huelīti mozaca zāzanilli tōcātzimpan \"$1\"",
- "immobile-target-namespace": "Ahmo huelīti mozaca zāzanilli tōcātzinhuīc \"$1\"",
- "immobile-source-page": "Ahmo huelīti mozacāz zāzanilli.",
+ "delete_and_move_confirm": "Quemah, ticpohpoloz in tlahcuilolamatl",
+ "immobile-source-namespace": "Ahmo hueli ticzaca inin tlahcuilolamatl ompa \"$1\"",
+ "immobile-target-namespace": "Ahmo hueli ticzaca inin tlahcuilolamatl ompa\"$1\"",
+ "immobile-source-page": "Ahmo hueli occepa tictocayotia inin tlahcuilolamatl.",
"move-leave-redirect": "Ma ticcahua ce tlatzonhuiliztli",
"export": "Tiquinnamacāz zāzaniltin",
"export-submit": "Ticnamacāz",
"allmessages-filter-all": "Mochi",
"allmessages-language": "Tlahtolli:",
"allmessages-filter-submit": "Tiyaz",
- "thumbnail-more": "Tiquihuēyiyāz",
+ "thumbnail-more": "Tichueyiyaz",
"thumbnail_error": "Aiuhcāyōtl ihcuāc mochīhuaya tepitōntli: $1",
"import": "Tiquincōhuāz zāzaniltin",
"import-interwiki-sourcewiki": "Mēyalhuiqui:",
"tooltip-ca-edit": "Ticpatlaz inin tlahcuilolli",
"tooltip-ca-addsection": "Ticpehualiz ce yancuic xeliuhcayotl.",
"tooltip-ca-viewsource": "Inīn zāzanilli ōmoquīxti. Tihuelīti tiquitta ītlahtōlcaquiliztilōni.",
- "tooltip-ca-history": "Achtopa āxcān zāzanilli īhuān in tlatequitiltilīlli ōquinchīuhqueh",
+ "tooltip-ca-history": "In tlein ye oquichiuhqueh ipan inin tlahcuilolamatl",
"tooltip-ca-protect": "Ticquīxtiāz inīn zāzanilli",
"tooltip-ca-delete": "Ticpolōz inīn zāzanilli",
"tooltip-ca-undelete": "Ahticpolōz inīn zāzanilli",
"tooltip-ca-move": "Ticzacaz inin tlahcuilolamatl",
- "tooltip-ca-watch": "Ticcentiliz inin tlahtolli motecpanaliz",
+ "tooltip-ca-watch": "Tictlaliz inin tlahcuilolamatl motlachiyaliz",
"tooltip-ca-unwatch": "Ticpohpoloz inin tlahcuilolamatl ipan motlachiyaliz",
"tooltip-search": "Tlatemoliztli ipan {{SITENAME}}",
"tooltip-search-go": "Tiyaz ihuicpa tlahcuilolamatl ica inin huel melahuac tocaitl intla oncah",
"tooltip-p-logo": "Tiquittaz in yacatlahcuilolli",
"tooltip-n-mainpage": "Tiquittaz in yacatlahcuilolli",
"tooltip-n-mainpage-description": "Tiquittaz in yacatlahcuilolli",
- "tooltip-n-portal": "Tlachīhualiztechcopa, inōn tihuelīti titlachīhua, tlatēmoyān",
- "tooltip-n-recentchanges": "Yancuic īpan tlapatlaliztli in huiqui",
+ "tooltip-n-portal": "Itech totequitiliz, in canin titlachihua, in canin titlatemoa",
+ "tooltip-n-recentchanges": "Iyancuictlapatlalizhuan ipan huiqui",
"tooltip-n-randompage": "Tiquittaz cecen tlahcuilolli",
- "tooltip-n-help": "In tēmachtīlōyān",
+ "tooltip-n-help": "In canin ticmachtiz",
"tooltip-t-whatlinkshere": "Mochintin tlahcuiloltin huiquipan quitzonhuiliah nican",
"tooltip-t-recentchangeslinked": "Yancuic tlapatlaliztli ipan tlahcuiloltin tlein quitzonhuilia nican",
"tooltip-feed-rss": "RSS tlachicahualiztli inin tlahcuilolamatl",
"tooltip-feed-atom": "Atom tlachicāhualiztli inīn zāzaniltechcopa",
"tooltip-t-contributions": "Tlapōhualmatl ītechpa {{GENDER:$1|inīn tlatequitiltilīlli}} ītlahcuilōl",
- "tooltip-t-emailuser": "Tiquihcuilōz inīn tlatequitiltililhuīc",
+ "tooltip-t-emailuser": "Tictitlantiz ce mail ihuicpa {{GENDER:$1|inin tequitiuhqui}}",
"tooltip-t-upload": "Tiquinquetzaz tlahcuiloltin",
"tooltip-t-specialpages": "Intlahtoltecpanaliz mochtin in noncuahquizquitlahcuiloltin",
"tooltip-t-print": "Tepoztlahcuilolli",
"tooltip-ca-nstab-main": "Tiquittaz tlein quipiya in tlahcuilolli",
"tooltip-ca-nstab-user": "Xiquitta tequitiuhqui itlahcuilolamauh",
- "tooltip-ca-nstab-special": "Inīn nōncuahquīzqui āmatl, auh ahmohuelitizpatla",
+ "tooltip-ca-nstab-special": "Inin noncuahquizqui amatl, auh ahmohueli in ticpatlaz",
"tooltip-ca-nstab-project": "Xiquitta in tlayecantequitl itlahcuilolamauh",
- "tooltip-ca-nstab-image": "Xiquittāz īxipzāzanilli",
+ "tooltip-ca-nstab-image": "Xiquittaz tlahcuilolpiyalli",
"tooltip-ca-nstab-mediawiki": "Xiquitta in tlahcuilōltzin",
"tooltip-ca-nstab-template": "Xiquitta in nemachiyōtīlli",
"tooltip-ca-nstab-help": "Xiquitta in tēpalēhuiliztli zāzanilli",
"tooltip-summary": "Xiquihcuilo ce tepiton tlahcuiloltontli",
"anonymous": "Ahtōcāitl {{PLURAL:$1|tlatequitiltilīlli}} īpan {{SITENAME}}",
"siteuser": "$1 tlatequitiltilīlli īpan {{SITENAME}}",
- "lastmodifiedatby": "Inin tlahcuilolamatl omopatlac ipan $2, $1 ipal $3.",
+ "lastmodifiedatby": "$3 oquipatlac inin tlahcuilolamatl ipan tonalli $1 immanin $2.",
"others": "occequīntīn",
"siteusers": "$1 {{PLURAL:$2|{{GENDER:$1|tequitiuhqui}}|tequitiuhqueh}} īpan {{SITENAME}}",
"spam_reverting": "Mocuepacah īhuīc xōcoyōc tlapatlaliztli ahmo tzonhuilizca īhuīc $1",
"exif-lightsource-1": "Tōnameyōtl",
"exif-lightsource-2": "Nāltic",
"exif-lightsource-4": "Flax",
- "exif-lightsource-10": "Mixxoh",
- "exif-lightsource-11": "Ecahuīlli",
- "exif-lightsource-12": "Nāltic tōnallāhuīlli (D 5700 – 7100K)",
- "exif-lightsource-13": "Nāltic iztāc tōnallāhuīlli (N 4600 – 5400K)",
- "exif-lightsource-14": "Nāltic cecec iztāc (W 3900 – 4500K)",
+ "exif-lightsource-10": "Mixtentoc",
+ "exif-lightsource-11": "Ecahuilloh",
+ "exif-lightsource-12": "Naltonac (D 5700 – 7100K)",
+ "exif-lightsource-13": "Iztac naltonac (N 4600 – 5400K)",
+ "exif-lightsource-14": "Cecec iztac naltonac (W 3900 – 4500K)",
"exif-lightsource-15": "Nāltic iztāc (WW 3200 – 3700K)",
"exif-lightsource-17": "Yēctli tlāhuīlli A",
"exif-lightsource-18": "Yēctli tlāhuīlli B",
"scarytranscludetoolong": "[In URL huel hueyac]",
"recreate": "Ticchīhuāz occeppa",
"confirm_purge_button": "Cualli",
- "imgmultipageprev": "← achto zāzanilli",
- "imgmultipagenext": "niman zāzanilli →",
+ "imgmultipageprev": "← achto tlahcuilolamatl",
+ "imgmultipagenext": "niman tlahcuilolamatl →",
"imgmultigo": "¡Ma xiyauh!",
"imgmultigoto": "Yaliztica ihuicpa tlahtolamatl $1",
"ascending_abbrev": "quetza",
"descending_abbrev": "temoa",
- "table_pager_next": "Niman zāzanilli",
- "table_pager_prev": "Achto zāzanilli",
- "table_pager_first": "Achtopa zāzanilli",
- "table_pager_last": "Xōcoyōc zāzanilli",
+ "table_pager_next": "Niman tlahcuilolamatl",
+ "table_pager_prev": "Achto tlahcuilolamatl",
+ "table_pager_first": "Achtopa tlahcuilolamatl",
+ "table_pager_last": "Xocoyoc tlahcuilolamatl",
"table_pager_limit_submit": "Yaliztica",
"table_pager_empty": "Ahtlein",
"autosumm-blank": "Tlaiztaliztli in tlahcuilolamatl",
"size-megabytes": "$1 MB",
"size-gigabytes": "$1 GB",
"watchlistedit-normal-title": "Ticpatlāz motlachiyaliz",
+ "watchlistedit-raw-titles": "Tlahcuilolamameh",
"watchlistedit-raw-added": "{{PLURAL:$1|Ōmocentili cē zāzanilli|Ōmocentilih $1 zāzaniltin}}:",
+ "watchlistedit-clear-titles": "Tocaitl",
"watchlisttools-view": "Tiquinttāz huēyi tlapatlaliztli",
"watchlisttools-edit": "Tiquittāz auh ticpatlāz motlachiyaliz",
"version": "Machiyōtzin",
"specialpages-group-highuse": "Zāzaniltin tlatequitiliztechcopa",
"specialpages-group-pages": "Mochintin tlahcuilolamameh",
"specialpages-group-redirects": "Tlatēmoliztli īhuān tlacuepaliztli",
- "blankpage": "Iztāc zāzanilli",
- "htmlform-selectorother-other": "Occe",
+ "blankpage": "Iztac tlahcuilolamatl",
+ "htmlform-selectorother-other": "Occequi",
"rightsnone": "ahtlein",
+ "feedback-cancel": "Moxitiniz",
"searchsuggest-search": "Tlatemoliztli",
"api-error-stashfailed": "Tlâtek îtlakawilistli: In tlatèmakani awel òkeuh in èwalpanòni.",
"api-error-unknown-warning": "Âmò ìxmatkàyo tlanawatilistli: \"$1\".",
"special-characters-group-thai": "Taitlahcuilōlli",
"special-characters-group-lao": "Laotlahcuilōlli",
"special-characters-group-khmer": "Jemertlahcuilōlli",
- "randomrootpage": "Zazantlen nelhuatlahcuilolamatl"
+ "randomrootpage": "Itech nepapan tlahcuilolamatl, iteyacatica"
}
"filereadonlyerror": "Kon t bestaand \"$1\" niet anpassen umdat de bestaandsmap \"$2\" op dit moment op allinnig-lezen steet.\n\nDe op-egeven reden is: \"$3\".",
"invalidtitle-knownnamespace": "Ongeldige titel mit naamruumte \"$2\" en tekste \"$3\"",
"invalidtitle-unknownnamespace": "Ongeldige titel mit onbekend naamruumtenummer $1 en tekste \"$2\"",
- "exception-nologin": "Nyt an-emeld",
+ "exception-nologin": "Neet an-emelded",
"exception-nologin-text": "Um disse zied te bekieken of disse haandeling uut te kunnen voeren mu'j [[Special:Userlogin|an-emeld]] ween bie disse wiki.",
"virus-badscanner": "Slichte konfigurasie: onbekend antivirusprogramma: ''$1''",
"virus-scanfailed": "inlezen is mislokt (kode $1)",
"nav-login-createaccount": "Anmelden",
"logout": "Ofmelden",
"userlogout": "Aofmelden",
- "notloggedin": "Nyt an-emeld",
+ "notloggedin": "Neet an-emelded",
"userlogin-noaccount": "Heb jy noch gyn gebrukersname?",
"userlogin-joinproject": "Wörd lid van {{SITENAME}}",
"createaccount": "Inskryven",
"enhancedrc-history": "geschiedenisse",
"recentchanges": "Lätste wysigingen",
"recentchanges-legend": "Opsies veur leste wiezigingen",
- "recentchanges-summary": "Op disse zied ku'j de leste wiezigingen van disse wiki bekieken.",
+ "recentchanges-summary": "Up disse syde kün jy de lätste wysigingen van disse wiki bekyken.",
"recentchanges-noresult": "Der waren in disse periode gien wiezigingen die an de kriteria voldoon.",
"recentchanges-feed-description": "Zeuk naor de alderleste wiezingen op disse wiki in disse voer.",
- "recentchanges-label-newpage": "Mid disse bewarking is een nye syde an-emaakt",
- "recentchanges-label-minor": "Dit is een kleyne wysiging",
+ "recentchanges-label-newpage": "Mid disse bewarking is een nye syde an-emaked",
+ "recentchanges-label-minor": "Dit is een kleine wysiging",
"recentchanges-label-bot": "Disse bewarking is uutevoord döär een bot",
- "recentchanges-label-unpatrolled": "Disse bewarking is noch nyt nå-ekeaken",
+ "recentchanges-label-unpatrolled": "Disse bewarking is noch neet nå-ekeaken",
"recentchanges-label-plusminus": "Disse sydegroutte is mid dit antal bytes ewysigd",
"recentchanges-legend-heading": "<strong>Legenda:</strong>",
- "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (sy ouk de [[Special:NewPages|lyste mid nye syden]])",
+ "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (see ouk de [[Special:NewPages|lyste mid nye syden]])",
"recentchanges-submit": "Bekiek",
"rcfilters-legend-heading": "<strong>Lyste mid ofkortingen:</strong>",
"rcfilters-group-results-by-page": "Resultaoten per zied groeperen",
"rcfilters-savedqueries-add-new-title": "Filterinstellingen upslån",
"rcfilters-restore-default-filters": "Standardfilters weerummezetten",
"rcfilters-clear-all-filters": "Alle filters vortdoon",
- "rcfilters-search-placeholder": "Filter wysigingen (gebruuk et menu of söök up filtername)",
+ "rcfilters-search-placeholder": "Filter wysigingen (gebruuk et menü of söök up filtername)",
"rcfilters-filterlist-feedbacklink": "Låt uns weaten wat jy van disse (nye) filterhülpmiddels vinden",
"rcfilters-highlightbutton-title": "Resultåten markeren",
"rcfilters-highlightmenu-title": "Kies n kleur",
"rcfilters-filtergroup-userExpLevel": "Gebrukersanmelding en ervåring",
"rcfilters-filter-user-experience-level-registered-label": "An-emeld",
"rcfilters-filter-user-experience-level-registered-description": "An-emelde bewarkers.",
- "rcfilters-filter-user-experience-level-unregistered-label": "Nyt an-emeld",
- "rcfilters-filter-user-experience-level-unregistered-description": "Bewarkers dy nyt an-emeld binnen.",
+ "rcfilters-filter-user-experience-level-unregistered-label": "Neet an-emelded",
+ "rcfilters-filter-user-experience-level-unregistered-description": "Bewarkers dee neet an-emelded binnen.",
"rcfilters-filter-user-experience-level-newcomer-label": "Anwas",
- "rcfilters-filter-user-experience-level-newcomer-description": "An-emelde bewarkers dy minder as 10 bewarkingen edån hebben of 4 dagen aktiv ewest binnen.",
+ "rcfilters-filter-user-experience-level-newcomer-description": "An-emelden bewarkers dee minder as 10 bewarkingen edån hebben of 4 dagen aktiv ewesd hebben.",
"rcfilters-filter-user-experience-level-learner-label": "Learlingen",
- "rcfilters-filter-user-experience-level-learner-description": "An-emelde bewarkers mid meer ervåring as \"anwas\", mär minder as \"ervåren gebrukers\".",
+ "rcfilters-filter-user-experience-level-learner-description": "An-emelde bewarkers mid meyr ervåring as \"anwas\", mär minder as \"ervåren gebrukers\".",
"rcfilters-filter-user-experience-level-experienced-label": "Ervåren gebrukers",
- "rcfilters-filter-user-experience-level-experienced-description": "An-emelde bewarkers mid meer as 500 bewarkingen en 30 dagen van aktiviteyt.",
+ "rcfilters-filter-user-experience-level-experienced-description": "An-emelde bewarkers mid meyr as 500 bewarkingen en 30 dagen van aktiviteit.",
"rcfilters-filter-bots-label": "Bot",
- "rcfilters-filter-humans-label": "Meanskelik (gyn bot)",
+ "rcfilters-filter-humans-label": "Meanskelik (geyn bot)",
"rcfilters-filter-humans-description": "Bewarkingen döär meanskelike bewarkers.",
"rcfilters-filtergroup-reviewstatus": "Beoordelingsstaotus",
"rcfilters-filter-reviewstatus-unpatrolled-label": "Niet nao-ekeken",
"rcfilters-filtergroup-significance": "Petansie",
- "rcfilters-filter-minor-label": "Kleyne bewarkingen",
- "rcfilters-filter-major-label": "Gyn kleyne bewarking",
+ "rcfilters-filter-minor-label": "Kleine bewarkingen",
+ "rcfilters-filter-minor-description": "Bewarkingen dee döär de bewarker emarkeerd binnen as klein.",
+ "rcfilters-filter-major-label": "Geyn kleine bewarking",
"rcfilters-filter-major-description": "Bewarkingen niet emarkeerd as klein.",
"rcfilters-filtergroup-watchlist": "Evolgde ziejen",
"rcfilters-filter-watchlist-watched-label": "Op de volglieste",
"rcfilters-filter-watchlist-watchednew-label": "Nieje volgliestwiezigingen",
"rcfilters-filter-watchlist-notwatched-label": "Niet op de volglieste",
"rcfilters-filter-watchlist-notwatched-description": "Alles behalve wiezigingen an ziejen die op joew volglieste staon.",
+ "rcfilters-filtergroup-changetype": "Soort wysiging",
"rcfilters-filter-pageedits-label": "Sydebewarkingen",
"rcfilters-filter-pageedits-description": "Wysigingen an de wiki-inhold, diskussys, kategorybeskryvingen…",
"rcfilters-filter-newpages-label": "Nye syden",
"rcfilters-filter-newpages-description": "Bewarkingen wårmead jy een nye syde anmaken.",
"rcfilters-filter-categorization-label": "Kategorywysigingen",
- "rcfilters-filter-categorization-description": "Upgave van syden dy tovoogd of vortedån wörden uut kategoryen.",
+ "rcfilters-filter-categorization-description": "Upgave van syden dee to-evoogd of vortedån wörden uut kategoryen.",
"rcfilters-filter-logactions-label": "Eregistreerde aktys",
+ "rcfilters-filter-logactions-description": "Administrative handelingen, nye kontos, et vortdoon van syden, upstüren van bestanden…",
"rcfilters-filtergroup-lastRevision": "Lätste versys",
"rcfilters-filter-lastrevision-label": "Lätste versy",
"rcfilters-filter-lastrevision-description": "Allinnig de lätste wysiging an een syde.",
- "rcfilters-filter-previousrevision-label": "Nyt de lätste versy",
- "rcfilters-filter-previousrevision-description": "Alle wysigingen dy nyt de \"lätste versy\" binnen.",
+ "rcfilters-filter-previousrevision-label": "Neet de lätste versy",
+ "rcfilters-filter-previousrevision-description": "Alle wysigingen dee neet de \"lätste versy\" binnen.",
"rcfilters-view-namespaces-tooltip": "Filter resultåten up naamruumte",
"rcfilters-view-tags-tooltip": "Filter resultåten döär gebruuk te maken van bewarkingsetiketten",
"rcfilters-liveupdates-button": "Rechtstreakse aktualisering",
"uploadbtn": "Bestand upstüren",
"reuploaddesc": "Weerumme naor de opstuurzied",
"upload-tryagain": "Bestaandsbeschrieving biewarken",
- "uploadnologin": "Nyt an-emeld",
+ "uploadnologin": "Neet an-emelded",
"uploadnologintext": "Je mutten $1 ween um bestaanden op te kunnen sturen.",
"upload_directory_missing": "De inlaojmap veur bestaanden ($1) is vort en kon niet an-emaakt wörden deur de webserver.",
"upload_directory_read_only": "Op t moment ku'j gien bestaanden opsturen vanwegen techniese problemen ($1).",
"listgrouprights-addgroup-self-all": "Kan alle groepen bie de eigen gebruker doon",
"listgrouprights-removegroup-self-all": "Kan alle groepen vortdoon van eigen gebruker",
"trackingcategories": "Volgkategorieën",
- "mailnologin": "Nyt an-emeld.",
+ "mailnologin": "Neet an-emelded.",
"mailnologintext": "Je mutten [[Special:UserLogin|an-emeld]] ween en n geldig e-mailadres in \"[[Special:Preferences|mien veurkeuren]]\" invoeren um disse funksie te kunnen gebruken.",
"emailuser": "Gebruker een bericht stüren",
"emailuser-title-target": "Disse {{GENDER:$1|gebruker}} n bericht sturen",
"watchlistfor2": "Veur $1 ($2)",
"nowatchlist": "Gien artikels in volglieste.",
"watchlistanontext": "$1 is verplicht um joew volglieste te bekieken of te wiezigen.",
- "watchnologin": "Nyt an-emeld",
+ "watchnologin": "Neet an-emelded",
"addwatch": "Op mien volglieste zetten",
"addedwatchtext": "De zied \"[[:$1]]\" steet noen op joew [[Special:Watchlist|volglieste]].\nToekomstige wiezigingen op disse zied en de overlegzied zullen hier vermeld wörden.",
"removewatch": "Van mien volglieste aofhaolen",
"movepage-page-moved": "De zied $1 is herneumd naor $2.",
"movepage-page-unmoved": "De zied $1 kon niet herneumd wörden naor $2.",
"movepage-max-pages": "t Maximale antal automaties te herneumen ziejen is bereikt ({{PLURAL:$1|$1|$1}}).\nDe aandere ziejen wörden niet automaties herneumd.",
- "movelogpage": "Herneumlogboek",
+ "movelogpage": "Hernöömlogbook",
"movelogpagetext": "Hieronder steet n lieste mit ziejen die herneumd bin.",
"movesubpage": "{{PLURAL:$1|Zied die deronder hank|Ziejen die deronder hangen}}",
"movesubpagetext": "De {{PLURAL:$1|zied die onder disse zied hank|$1 ziejen die onder disse zied hangen}} vie'j hieronder.",
"table_pager_empty": "Gien resultaoten",
"autosumm-blank": "Zied leegemaakt",
"autosumm-replace": "Tekste vervöngen deur '$1'",
- "autoredircomment": "deurverwiezing naor [[$1]]",
+ "autoredircomment": "döärverwysing når [[$1]]",
"autosumm-new": "Nieje zied: '$1'",
"size-kilobytes": "$1 kB",
"lag-warn-normal": "Wiezigingen die niejer bin as $1 {{PLURAL:$1|seconde|seconden}} staon misschien nog niet in de lieste.",
"tag-filter": "[[Special:Tags|Etiketfilter]]:",
"tag-filter-submit": "Filtreren",
"tag-list-wrapper": "([[Special:Tags|Etiket{{PLURAL:$1||ten}}]]: $2)",
+ "tag-mw-new-redirect": "Nye döärverwysing",
+ "tag-mw-removed-redirect": "Döärverwysing vortedån",
"tags-title": "Etiket",
"tags-intro": "Op disse zied staon de etiketten waormee de programmatuur elke bewarking kan markeren, en de betekenisse dervan.",
"tags-tag": "Etiketnaam",
"htmlform-no": "Nee",
"htmlform-yes": "Ja",
"htmlform-chosen-placeholder": "Kies n opsie",
- "logentry-delete-delete": "$1 hef de zied $3 {{GENDER:$2|vortedaon}}",
+ "logentry-delete-delete": "$1 hevt de syde $3 {{GENDER:$2|vortedån}}",
"logentry-delete-restore": "$1 hef de zied $3 {{GENDER:$2|weerummezet}}",
"logentry-delete-event": "$1 hef de zichtbaorheid van {{PLURAL:$5|n logboekregel|$5 logboekregels}} van $3 {{GENDER:$2|ewiezigd}}: $4",
"logentry-delete-revision": "$1 hef de zichtbaorheid van {{PLURAL:$5|een versie|$5 versies}} van de zied $3 {{GENDER:$2|ewiezigd}}: $4",
"revdelete-unrestricted": "hef beparkingen veur beheerders deraof ehaold",
"logentry-block-block": "$1 {{GENDER:$2|hef}} {{GENDER:$4|$3}} eblokkeerd veur de duur van $5 $6",
"logentry-suppress-block": "$1 {{GENDER:$2|hef}} {{GENDER:$4|$3}} eblokkeerd veur de duur van $5 $6",
- "logentry-move-move": "$1 hef de zied $3 {{GENDER:$2|herneumd}} naor $4",
- "logentry-move-move-noredirect": "$1 hef de zied $3 {{GENDER:$2|herneumd}} naor $4 zonder n deurverwiezing achter te laoten",
- "logentry-move-move_redir": "$1 hef de zied $3 {{GENDER:$2|herneumd}} naor $4 over n deurverwiezing heer",
- "logentry-move-move_redir-noredirect": "$1 hef de zied $3 {{GENDER:$2|herneumd}} naor $4 over n deurverwiezing heer zonder n deurverwiezing achter te laoten",
+ "logentry-move-move": "$1 hevt de syde $3 {{GENDER:$2|hernöömd}} når $4",
+ "logentry-move-move-noredirect": "$1 hevt de syde $3 {{GENDER:$2|hernöömd}} når $4 sunder een döärverwysing achter te låten",
+ "logentry-move-move_redir": "$1 hevt de syde $3 {{GENDER:$2|hernöömd}} når $4 oaver een döärverwysing hear",
+ "logentry-move-move_redir-noredirect": "$1 hevt de syde $3 {{GENDER:$2|hernöömd}} når $4 oaver een döärverwysing hear sunder een döärverwysing achter te låten",
"logentry-patrol-patrol": "$1 hef versie $4 van de zied $3 op {{GENDER:$2|nao-ekeken}} ezet",
"logentry-patrol-patrol-auto": "$1 hef versie $4 van de zied $3 automaties op {{GENDER:$2|nao-ekeken}} ezet",
"logentry-newusers-newusers": "Gebruker $1 is {{GENDER:$2|an-emaakt}}",
"deadendpages": "Pagina's zonder koppelingen",
"deadendpagestext": "De onderstaande pagina's verwijzen niet naar andere pagina's in deze wiki.",
"protectedpages": "Beveiligde pagina's",
+ "protectedpages-filters": "Filters:",
"protectedpages-indef": "Alleen blokkades zonder vervaldatum",
"protectedpages-summary": "Deze pagina bevat een lijst met beveiligde pagina's. Zie [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]] voor een lijst van pagina's die niet aangemaakt mogen worden.",
"protectedpages-cascade": "Alleen beveiligingen met de cascade-optie",
"createacct-email-ph": "Entratz vòstra adreça de corrièr electronic",
"createacct-another-email-ph": "Picar l'adreça de corrièr electronic",
"createaccountmail": "Utilizar un senhal aleatòri temporari e lo mandar a l’adreça de corrièl especificada",
+ "createaccountmail-help": "Pòt s'utilizar per crear un compte per una autra persona sens conéisser lo mot de passa.",
"createacct-realname": "Nom vertadièr (facultatiu)",
"createacct-reason": "Motiu",
"createacct-reason-ph": "Perqué creatz un autre compte",
"wrongpassword": "Lo nom d'utilizaire o lo senhal es incorrècte.\nEnsajatz tornarmai.",
"wrongpasswordempty": "Lo senhal picat èra void. Se vos plai, ensajatz tornarmai.",
"passwordtooshort": "Vòstre senhal deu conténer al mens {{PLURAL:$1|1 caractèr|$1 caractèrs}}.",
+ "passwordtoolong": "Mots de passa pòdon pas aver mai de {{PLURAL:$1|1 caractèr|$1 caractèrs}}.",
+ "passwordtoopopular": "Es pas possible d'utilizar mots de passa fòrça comuns. Vos cal causir un mot de passa mai malaisit de deschifrar.",
"password-name-match": "Vòstre senhal deu èsser diferent de vòstre nom d’utilizaire.",
"password-login-forbidden": "L'usatge d'aquestes nom d'utilizaire e senhal es pas autorisat",
"mailmypassword": "Reïnicializar lo senhal",
"passwordreset-emailelement": "Utilizaire: \n$1\n\nSenhal temporari: \n$2",
"passwordreset-emailsentemail": "Se aquesta adreça de corrièl es associada a vòstre compte, alara un corrièl de reïnicializacion de senhal serà mandat.",
"passwordreset-emailsentusername": "Se i a una adreça de corrièr electronic associada a aqueste nom d’utilizaire, alara un corrièl de reïnicializacion senhal serà mandat.",
+ "passwordreset-nocaller": "Cal provesir un apelaire",
"passwordreset-nosuchcaller": "L’apelant existís pas : $1",
+ "passwordreset-ignored": "Lo restabliment del mot de passa s'es pas plan realizat. Benlèu i aviá pas cap de fornidor configurat?",
"passwordreset-invalidemail": "Adreça de corrièr electronic invalida",
+ "passwordreset-nodata": "Pas cap de nom d'usatgièr o d'adreça electronica foguèron provesits",
"changeemail": "Cambiar o suprimir l'adreça electronica",
"changeemail-header": "Completatz aqueste formulari per modificar vòstra adreça de corrièl. Se volètz suprimir l’associacion d’una adreça de corrièl amb vòstre compte, daissatz la novèla adreça de corrièl voida al moment de la somission del formulari.",
"changeemail-no-info": "Vos cal èsser connectat per aver accès a aquesta pagina.",
"changeemail-oldemail": "Adreça electronica actuala:",
"changeemail-newemail": "Novela adreça electronica:",
+ "changeemail-newemail-help": "Vos cal daissar aquel camp void se volètz suprimir la vòstra adreça electronica. Mas, se suprimètz aquela adreça poiretz pas tornar inicializar lo mot de passa se l'avètz doblidat e recebretz pas de corrièrs electronics dempuèi aquel wiki.",
"changeemail-none": "(pas cap)",
"changeemail-password": "Vòstre senhal sus {{SITENAME}} :",
"changeemail-submit": "Cambiar l'adreça electronica :",
"changeemail-throttled": "Avètz fait tròp de temptativas de connexion.\nEsperatz $1 abans d’ensajar tornarmai.",
+ "changeemail-nochange": "Vos cal picar una novèla adreça electronica, diferenta de la precedenta.",
"resettokens": "Reïnicializar los getons",
"resettokens-text": "Aici, podètz reïnicializar los getons que permeton d’accedir a d'unas donadas privadas associadas a vòstre compte.\n\nLo vos caldriá far se las avètz partejats accidentalament amb qualqu'un o se vòstre compte es estat compromés.",
"resettokens-no-tokens": "I a pas cap de geton de reïnicializar.",
"anoneditwarning": "<strong>Atencion :<strong> sètz pas connectat.\nVòstra adreça IP serà visibla per tot lo monde se fasètz de modificacions. Se <strong>[$1 vos connectatz]</strong> o <strong>[$2 creatz un compte]</strong>, vòstras modificacions seràn atribuidas a vòstre nom d’utilizaire, entre autres avantatges.",
"anonpreviewwarning": "''Sètz pas identificat. Salvar enregistrarà vòstra adreça IP dins l’istoric de las modificacions de la pagina.''",
"missingsummary": "'''Atencion :''' avètz pas modificat lo resumit de vòstra modificacion. Se clicatz tornarmai sul boton « Salvar », lo salvament serà fait sens avertiment mai.",
+ "selfredirect": "<strong>Atencion:</strong> Sètz a redirigir aquela pagina cap a se meteissa.\nPodètz aver especificat un faus objectiu per la redireccion, o benlèu avètz modificar una pagina incorrècta.\nSe tornatz faire un clic \"$1\" , la redireccion serà çaquelà creada.",
"missingcommenttext": "Mercé de metre un comentari.",
"missingcommentheader": "<strong>Rapèl :</strong> Avètz pas provesit cap de subjècte per aqueste comentari.\nSe clicatz tornamai sus « {{int:Savearticle}} », vòstra modificacion serà enregistrada sens subjècte.",
"summary-preview": "Apercebut del resumit de modificacion :",
"subject-preview": "Apercebut del subjècte :",
+ "previewerrortext": "S'es produsida una error quand ensagèretz de previsualizar los cambiaments.",
"blockedtitle": "L'utilizaire es blocat",
"blockedtext": "'''Vòstre compte d'utilizaire o vòstra adreça IP es estat blocat'''\n\nLo blocatge es estat efectuat per $1.\nLa rason invocada es la seguenta : ''$2''.\n\n* Començament del blocatge : $8\n* Expiracion del blocatge : $6\n* Compte blocat : $7.\n\nPodètz contactar $1 o un autre [[{{MediaWiki:Grouppage-sysop}}|administrator]] per ne discutir.\nPodètz pas utilizar la foncion « Mandar un corrièr electronic a aqueste utilizaire » que se una adreça de corrièr valida es especificada dins vòstras [[Special:Preferences|preferéncias]].\nVòstra adreça IP actuala es $3 e vòstre identificant de blocatge es #$5.\nIncluissètz aquesta adreça dins tota requèsta.",
"autoblockedtext": "Vòstra adreça IP es estada blocada automaticament perque es estada utilizada per un autre utilizaire, ele-meteis blocat per $1.\nLa rason invocadaa es :\n\n:''$2''\n\n* Començament del blocatge : $8\n* Expiracion del blocatge : $6\n* Compte blocat : $7\n\nPodètz contactar $1 o un dels autres [[{{MediaWiki:Grouppage-sysop}}|administrators]] per discutir d'aqueste blocatge.\n\nNotatz que podètz pas utilizar la foncionalitat \"Mandar un messatge a aqueste utilizaire\" tant qu'auretz pas una adreça e-mail enregistrada dins vòstras [[Special:Preferences|preferéncias]] e tant que seretz pas blocat per son utilizacion.\n\nVòstra adreça IP actuala es $3, e lo numèro de blocatge es $5.\nPrecisatz aquestas indicacions dins totas las requèstas que faretz.",
+ "systemblockedtext": "Lo vòstre nom d'usatgièr o adreça IP foguèt estat blocat automaticament pel MediaWiki.\nLo motiu balhat es:\n\n:<em>$2</em>\n\n* Començament del blocatge: $8\n* Fin del delai de blocatge: $6\n* Element pertocat: $7\n\nLa vòstra adreça IP actuala es $3.\nApondètz las donadas de mai amont per cada demanda que faretz.",
"blockednoreason": "Cap de rason balhada",
"whitelistedittext": "Vos cal èsser $1 per modificar las paginas.",
"confirmedittext": "Vos cal confirmar vòstra adreça electronica abans de modificar l'enciclopèdia. Picatz e validatz vòstra adreça electronica amb l'ajuda de la pagina [[Special:Preferences|preferéncias]].",
"yourtext": "Vòstre tèxte",
"storedversion": "Version enregistrada",
"editingold": "'''Atencion : sètz a modificar una version obsolèta d'aquesta pagina. Se salvatz, totas las modificacions efectuadas dempuèi aquesta version seràn perdudas.'''",
+ "unicode-support-fail": "Sembla que lo vòstre navigador es pas compatible amb Unicode. Aquò es necessari per modificar las paginas, la vòstra edicion foguèt pas salvagardada.",
"yourdiff": "Diferéncias",
"copyrightwarning": "Totas las contribucions a {{SITENAME}} son consideradas coma publicadas jols tèrmes de la $2 (vejatz $1 per mai de detalhs). Se desiratz pas que vòstres escrits sián modificats e distribuits a volontat, mercés de los sometre pas aicí.<br /> Nos prometètz tanben qu'avètz escrit aquò vos-meteis, o que l’avètz copiat d’una font provenent del domeni public, o d’una ressorsa liura.'''UTILIZETZ PAS DE TRABALHS JOS COPYRIGHT SENS AUTORIZACION EXPRÈSSA !'''",
"copyrightwarning2": "Totas las contribucions a {{SITENAME}} pòdon èsser modificadas o suprimidas per d’autres utilizaires. Se desiratz pas que vòstres escrits sián modificats e distribuits a volontat, mercés de los sometre pas aicí.<br /> Tanben nos prometètz qu'avètz escrit aquò vos-meteis, o que l’avètz copiat d’una font provenent del domeni public, o d’una ressorsa liura. (vejatz $1 per mai de detalhs). '''UTILIZETZ PAS DE TRABALHS JOS COPYRIGHT SENS AUTORIZACION EXPRÈSSA !'''",
+ "editpage-cannot-use-custom-model": "Lo modèl de contengut d'aquela pagina pòt pas èsser cambiat.",
"longpageerror": "'''ERROR : Lo tèxte qu'avètz somés fa {{PLURAL:$1|un Kio|$1 Kio}}, çò que depassa lo limit fixat a {{PLURAL:$2|un Kio|$2 Kio}}.'''. Pòt pas èsser salvat.",
"readonlywarning": "<strong>AVERTIMENT : La basa de donadas es estada verrolhada per d'operacions de mantenença. Doncas, poiretz pas publicar vòstras modificacions pel moment.</strong>\nL’administrator sistèma qu'an verrolhada la basa de donadas a donat l’explicacion seguenta : $1",
"protectedpagewarning": "'''AVERTIMENT : Aquesta pagina es protegida. Sols los utilizaires qu'an l'estatut d'administrator la p�don modificar. ''' La darri�ra entrada del jornal es afichada �aij�s per refer�ncia :",
"permissionserrors": "Error de permission",
"permissionserrorstext": "Avètz pas la permission d’efectuar l’operacion demandada per {{PLURAL:$1|la rason seguenta|las rasons seguentas}} :",
"permissionserrorstext-withaction": "Sètz pas autorizat(ada) a $2, per {{PLURAL:$1|la rason seguenta|las rasons seguentas}} :",
+ "contentmodelediterror": "Podètz pas modificar aquela revision perque lo sieu modèl de contengut es <code>$1</code>, qu'es diferent del modèl de contengut actual de la pagina <code>$2</code>.",
"recreate-moveddeleted-warn": "'''Atencion : sètz a tornar crear una pagina qu'es estada suprimida precedentament.'''\n\nDemandatz-vos s'es vertadièrament apropriat de contunhar de l’editar.\nL’istoric de las supressions e dels cambiaments de nom es afichat çaijós :",
"moveddeleted-notice": "Aquesta pagina es estada suprimida.\nLo jornal de las supressions, de las proteccions e dels desplaçaments de la pagina es afichat çaijós per referéncia.",
+ "moveddeleted-notice-recent": "Desolat, aquela pagina foguèt recentament suprimida (en las darrièras 24 oras).\nPodètz consultar lo registre de las supressions, proteccions e dels renomenatges de la pagina çai-jos.",
"log-fulllog": "Veire lo jornal complet",
"edit-hook-aborted": "Modificacion fracassada per croquet.\nCap d'explicacion pas balhada.",
"edit-gone-missing": "A pas pogut metre a jorn la pagina.\nSembla que siá estada suprimida.",
"postedit-confirmation-created": "La pagina es estada creada.",
"postedit-confirmation-restored": "La pagina es estada restablida.",
"postedit-confirmation-saved": "Vòstra modificacion es estada salvada.",
+ "postedit-confirmation-published": "La vòstra modificacion foguèt publicada.",
"edit-already-exists": "La pagina novèla a pogut èsser creada .\nExistís ja.",
"defaultmessagetext": "Messatge per defaut",
"content-failed-to-parse": "Fracàs de l'analisi del contengut de $2 pel modèl $1: $3",
"invalid-content-data": "Donadas del contengut invalidas",
"content-not-allowed-here": "Lo contengut \"$1\" es pas autorizat sus la pagina [[$2]]",
"editwarning-warning": "Quitar aquesta pagina vos farà pèrdre totas las modificacions qu'avètz faitas.\nSe sètz connectat, podètz desactivar aqueste avertiment dins la seccion « {{int:prefs-editing}} » de vòstras preferéncias.",
+ "editpage-invalidcontentmodel-title": "Modèl de contengut pas permés",
+ "editpage-invalidcontentmodel-text": "Lo modèl de contengut «$1» es pas permés.",
"editpage-notsupportedcontentformat-title": "Format de contengut pas pres en carga",
"editpage-notsupportedcontentformat-text": "Lo format de contengut $1 es pas pres en carga pel modèl de contengut $2 .",
"content-model-wikitext": "wikitèxte",
"expansion-depth-exceeded-warning": "Pagina depassant la prigondor d'espandiment",
"parser-unstrip-loop-warning": "Bocla pas desmontabla detectada",
"unstrip-depth-warning": "Limit de recursion pas desmontable depassat ($1)",
+ "unstrip-depth-category": "Paginas que la limita de prigondor de desvolopament i es despassada",
+ "unstrip-size-warning": "Limita de mesura de desvolopament despassada ($1)",
+ "unstrip-size-category": "Paginas que la limita de la mesura de desvolopament es despassada",
"converter-manual-rule-error": "Error detectada dins la règla manuala de conversion de lenga",
"undo-success": "Aquesta modificacion va èsser desfaita. Confirmatz los cambiaments (visibles en bas d'aquesta pagina), puèi salvatz se sètz d’acòrdi. Mercés de motivar l’anullacion dins la bóstia de resumit.",
"undo-failure": "Aquesta modificacion a pas pogut èsser desfaita a causa de conflictes amb de modificacions intermediàrias.",
"mergehistory-fail-bad-timestamp": "L’orodatatge es pas valid.",
"mergehistory-fail-invalid-source": "La pagina font es pas valida.",
"mergehistory-fail-invalid-dest": "La pagina de destinacion es invalida",
+ "mergehistory-fail-no-change": "La fusion d'istoric a pas fusionat cap de revision. Tornatz verificar la pagina e los paramètres de temps.",
+ "mergehistory-fail-permission": "Avètz pas de permissions sufisentas per fusionar l'istoric.",
+ "mergehistory-fail-self-merge": "Las paginas d'origina e de destinacion son las meteissas",
+ "mergehistory-fail-timestamps-overlap": "Las revisions d'origina se superpausan o seguisson las de destinacion.",
"mergehistory-fail-toobig": "Impossible d’efectuar la fusion de l’istoric perque un nombre de {{PLURAL:$1|revisions}} superior al limit de $1 deuriá èsser desplaçat.",
"mergehistory-no-source": "La pagina d'origina $1 existís pas.",
"mergehistory-no-destination": "La pagina de destinacion $1 existís pas.",
"diff-multi-sameuser": "({{PLURAL:$1|Una revision intermediària pel meteis utilizaire pas afichada|$1 revisions intermediàrias pel meteis utilizaire pas afichadas}})",
"diff-multi-otherusers": "({{PLURAL:$1|Una revision intermediària|$1 revisions intermediàrias}} per {{PLURAL:$2|un autre utilizaire|$2 utilizaires}} pas {{PLURAL:$1|afichada|afichadas}})",
"diff-multi-manyusers": "({{PLURAL:$1|Una revision intermediària amagada|$1 revisions intermediàrias amagadas}}) per ({{PLURAL:$2|un utilizaire pas afichada|$2 utilizaires pas afichadas}})",
+ "diff-paragraph-moved-tonew": "Lo paragraf foguèt desplaçat. Fasètz un clic per anar a l'emplaçament nòu.",
+ "diff-paragraph-moved-toold": "Lo paragraf foguèt desplaçat. Fasètz un clic par anar a l'emplaçament ancian.",
"difference-missing-revision": "{{PLURAL:$2|Una revision|$2 revisions}} d'aquesta diferéncia ($1) {{PLURAL:$2|es pas estada trobada|son pas estadas trobadas}}.\n\nAquò se produtz en general en seguent un ligam de diferéncia obsolèta cap a una pagina qu'es estada suprimada.\nPodètz trobar de detalhs dins lo [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} jornal de las supressions].",
"searchresults": "Resultats de la recèrca",
"searchresults-title": "Resultats de la recèrca per « $1 »",
"search-category": "(categoria $1)",
"search-file-match": "(correspond al contengut del fichièr)",
"search-suggest": "Avètz volgut dire : $1",
+ "search-rewritten": "S’i mòstran los resultats de $1. Cercatz «$2» en luòc d'aquò.",
"search-interwiki-caption": "Resultats dels projèctes fraires",
"search-interwiki-default": "Resultats de $1 :",
"search-interwiki-more": "(mai)",
"search-external": "Recèrca extèrna",
"searchdisabled": "La recèrca sus {{SITENAME}} es desactivada.\nEn esperant la reactivacion, podètz efectuar una recèrca via Google.\nAtencion, lor indexacion de contengut {{SITENAME}} benlèu es pas a jorn.",
"search-error": "Una error s'es produita en recercant : $1",
+ "search-warning": "Una error s'es produsida en cercant : $1",
"preferences": "Preferéncias",
"mypreferences": "Preferéncias",
"prefs-edits": "Nombre d’edicions :",
"stub-threshold-disabled": "Desactivat",
"recentchangesdays": "Nombre de jorns d'afichar dins los darrièrs cambiaments :",
"recentchangesdays-max": "(maximum $1 {{PLURAL:$1|jorn|jorns}})",
- "recentchangescount": "Nombre de modificacions d'afichar per defaut :",
- "prefs-help-recentchangescount": "Aquò inclutz las modificacions recentas, las paginas d’istorics e los jornals.",
+ "recentchangescount": "Nombre de modificacions d'afichar per defauta dins los cambiaments recents, los istorics e los logs :",
+ "prefs-help-recentchangescount": "Nombre maximum : 1000",
"prefs-help-watchlist-token2": "Aquí la clau secreta del flux Web de vòstra lista de seguiment.\nTota persona que la coneis poirà legir vòstra lista de seguiment, doncas, la comuniquetz pas.\nSe necessari, [[Special:ResetTokens|clicatz aicí per la reïnicializar]].",
"savedprefs": "Las preferéncias son estadas salvadas.",
"savedrights": "Los dreits d'utilizaire de {{GENDER:$1|$1}} son estats enregistrats.",
"timezoneregion-indian": "Ocean Indian",
"timezoneregion-pacific": "Ocean Pacific",
"allowemail": "Autorizar los autres utilizaires a me mandar de corrièls",
+ "email-allow-new-users-label": "Autorizar corrièr electronic d'utilizaires nòus",
"prefs-searchoptions": "Recèrca",
"prefs-namespaces": "Noms d’espacis",
"default": "defaut",
"deleting-backlinks-warning": "گواښنه:''' دا مخ چې تاسې يې ړنگوی د [[Special:WhatLinksHere/{{FULLPAGENAME}}|نورو مخونو]] سره تړلی او يا هم په نورو مخونو کې نغاړل شوی دی.",
"rollbacklink": "په شابېول",
"rollbacklinkcount": "$1 {{PLURAL:$1|سمون|سمونونه}} پرشابېول",
+ "rollbacklinkcount-morethan": "تر $1 زيات {{PLURAL:$1|بدلون|بدلونونه}} پرشا بوځي",
"editcomment": "د سمون لنډيز دا وو: \"''$1''\".",
"changecontentmodel-title-label": "مخ سرليک",
"changecontentmodel-model-label": "د نوي مېنځپانگې موډل",
"limitreport-expansiondepth-value": "$1/$2",
"limitreport-expensivefunctioncount": "د قیمتي پارسير فعالیت شمیرې",
"limitreport-expensivefunctioncount-value": "$1/$2",
+ "limitreport-unstrip-size-value": "$1/$2 {{PLURAL:$2|ټکۍ|ټکي}}",
"expandtemplates": "کينډۍ غځول",
"expand_templates_intro": "په دا ځانګړي مخ کي متن پاڼه ترلاسه کیږي کوم چي په ټول ډوله مخونو کي کارول کیږي دلته دا مخ بيا بیا وده کوي. د تحلیل دندو لکه <code><nowiki>{{</nowiki>#language:…}}</code> او متغیرونه لکه <code><nowiki>{{</nowiki>CURRENTDAY}}</code> هم سره نښلوي — په واقعیت کې، د ډلو دننه هر څه. دا خپله د ميډياويکي په اړونده مرحله کولو سره ترسره کيږي.",
"expand_templates_title": "د موزوع سرليک، د {{FULLPAGENAME}} لپاره او نور:",
"restrictionsfield-badip": "ناباوره آي پي آدرس او حدود د : $1",
"restrictionsfield-label": "اجازه ورکړل شوي آي پي حدودونه:",
"restrictionsfield-help": "په هر کرښه کې د اي پي پته یا د سینیر رینټ داخل کړئ. د هر شی فعالولو لپاره دا ارزښت وکاروئ: <code>0.0.0.0/0</code><br /><code>::/0</code>",
+ "edit-error-short": "تيروتنه: $1",
+ "edit-error-long": "تيروتنې:$1",
"revid": "بیاکتنه $1",
"pageid": "د مخ پېژند$1",
"rawhtml-notallowed": "لیبلونه <html> د منظمو ليکنو څخه بهر نشي کارول کیدی.",
"Gombang",
"Trizek (WMF)",
"Acamicamacaraca",
- "Avatar6"
+ "Avatar6",
+ "Akapochtli"
]
},
"sidebar": "{{notranslate}}",
"minoredit": "Midà be bagatellas",
"watchthis": "Observar quest artitgel",
"savearticle": "Memorisar la pagina",
+ "publishchanges": "Publitgar midadas",
"preview": "Prevista",
"showpreview": "Mussar prevista",
"showdiff": "Mussar midadas",
"rcfilters-filter-bots-description": "Modificări făcute cu unelte automate.",
"rcfilters-filter-humans-label": "Om (nu robot)",
"rcfilters-filter-humans-description": "Modificări făcute de oameni.",
- "rcfilters-filtergroup-reviewstatus": "Revizuiți starea",
+ "rcfilters-filtergroup-reviewstatus": "Statutul reviziei",
"rcfilters-filter-reviewstatus-unpatrolled-label": "Nepatrulate",
"rcfilters-filtergroup-significance": "Semnificație",
"rcfilters-filter-minor-label": "Modificări minore",
"rcfilters-filter-watchlistactivity-seen-label": "Schimbări văzute",
"rcfilters-filter-watchlistactivity-seen-description": "Modificările paginilor pe care le-ați vizitat de la efectuarea schimbărilor.",
"rcfilters-filtergroup-changetype": "Tipul modificării",
- "rcfilters-filter-pageedits-label": "Editări ale paginii",
+ "rcfilters-filter-pageedits-label": "Modificări în pagini",
"rcfilters-filter-pageedits-description": "Editări ale conținutului wiki, discuții, descrieri de categorii…",
"rcfilters-filter-newpages-label": "Creare de pagini",
"rcfilters-filter-newpages-description": "Modificări care au dus la crearea de pagini noi.",
"imagelinks": "Использование файла",
"linkstoimage": "{{PLURAL:$1|Следующая $1 страница ссылается|Следующие $1 страницы ссылаются|Следующие $1 страниц ссылаются}} на данный файл:",
"linkstoimage-more": "Более $1 {{PLURAL:$1|страницы|страниц}} ссылаются на этот файл.\nВ данном списке {{PLURAL:$1|представлена только $1 ссылка|представлены только $1 ссылки|представлены только $1 ссылок}} на этот файл.\nДоступен также [[Special:WhatLinksHere/$2|полный список]].",
- "nolinkstoimage": "Нет страниц, ссылающихся на данный файл.",
+ "nolinkstoimage": "Нет страниц, включающих этот файл.",
"morelinkstoimage": "Просмотреть [[Special:WhatLinksHere/$1|остальные ссылки]] на этот файл.",
"linkstoimage-redirect": "$1 (файловое перенаправление) $2",
"duplicatesoffile": "{{PLURAL:$1|Следующий файл является дубликатом|Следующие $1 файла являются дубликатами|Следующие $1 файлов являются дубликатами}} этого файла ([[Special:FileDuplicateSearch/$2|подробности]]):",
"MtDu",
"Manik Soren",
"Ramjit Tudu",
- "R Ashwani Banjan Murmu"
+ "R Ashwani Banjan Murmu",
+ "Fagunkoyel Hansdah"
]
},
"tog-underline": "ᱡᱚᱱᱚᱲ ᱞᱟᱛᱟᱨᱨᱮ ᱫᱟᱜᱽ ᱩᱫᱩᱜᱽᱢᱮ:",
"pool-timeout": "Somoy paromena cạbi lạgit́te tạṅgi hoyoḱkana",
"pool-queuefull": "Pool queue is full",
"pool-errorunknown": "ᱵᱟᱝ ᱵᱟᱰᱟᱭ ᱦᱩᱲᱟᱹᱜ",
- "aboutsite": "ᱵᱟᱵᱚᱛ {{SITENAME}}",
+ "aboutsite": "{{SITENAME}} ᱵᱟᱵᱚᱛ",
"aboutpage": "Project: ᱵᱟᱵᱚᱛ",
"copyright": "ᱩᱱᱩᱫᱩᱜ ᱫᱚ ᱧᱟᱢᱚᱜ-ᱟ $1 ᱞᱮᱠᱟᱛᱮ ᱵᱟᱝᱠᱷᱟᱱ ᱚᱞ ᱛᱟᱦᱮᱱᱟ",
"copyrightpage": "{{ns:project}}: ᱮᱠᱛᱤᱭᱟᱨ",
"listfiles_date": "ᱢᱟᱹᱦᱤᱛ",
"listfiles_name": "ᱧᱩᱛᱩᱢ",
"listfiles_user": "ᱵᱮᱵᱦᱟᱨᱤᱡ",
+ "listfiles-latestversion-yes": "ᱦᱮᱸ",
+ "listfiles-latestversion-no": "ᱵᱟᱝ",
"file-anchor-link": "ᱨᱮᱫ",
"filehist": "ᱨᱮᱫ ᱨᱮᱭᱟᱜ ᱱᱟᱜᱟᱢ",
"filehist-help": "ᱚᱠᱛᱚ ᱨᱮ ᱞᱤᱱ ᱢᱮ/ᱚᱠᱛᱚ ᱨᱮ ᱨᱮᱫ ᱧᱮᱞ ᱞᱟᱹᱜᱤᱛ ᱞᱤᱱ ᱢᱮ",
"filehist-nothumb": "ᱵᱟᱹᱱᱩᱜ-ᱟ ᱴᱤᱯ-ᱨᱟᱢᱟ",
"filehist-user": "ᱵᱮᱵᱦᱟᱨᱤᱡ",
"filehist-dimensions": "ᱡᱚᱠᱷᱟ",
+ "filehist-filesize": "ᱨᱮᱫ ᱥᱟᱭᱤᱡᱽ",
"filehist-comment": "ᱠᱟᱛᱷᱟ",
"imagelinks": "ᱯᱷᱟᱭᱤᱞ ᱵᱮᱣᱦᱟᱨ",
"linkstoimage": "ᱞᱟᱛᱟᱨ ᱨᱮᱭᱟᱜ {{PLURAL:$1|ᱥᱟᱦᱴᱟ ᱡᱚᱱᱚᱲᱠᱚ|$1 ᱥᱟᱦᱴᱟᱠᱚ ᱡᱚᱱᱚᱲ}} ᱱᱤᱭᱟᱹ ᱨᱮᱫ ᱨᱮ:",
"sharedupload-desc-here": "ᱱᱚᱣᱟ ᱨᱮᱫ ᱫᱚ ᱱᱚᱸᱰᱮ ᱠᱷᱚᱱ $1 ᱟᱨ ᱯᱟᱥᱮᱡ ᱮᱴᱟᱜ-ᱟ ᱯᱚᱨᱡᱮᱠᱴ ᱨᱮᱦᱚᱸ ᱵᱮᱵᱦᱟᱨᱚᱜ ᱠᱟᱱᱟ᱾\nᱱᱚᱣᱟ ᱨᱮᱭᱟ ᱯᱟᱥᱱᱟᱣ ᱠᱟᱛᱷᱟ [$2 ᱨᱮᱫ ᱯᱟᱥᱱᱟᱣ ᱥᱟᱦᱴᱟ] ᱞᱟᱛᱟᱨᱨᱮ ᱮᱢ ᱮᱱᱟ᱾",
"filepage-nofile": "ᱱᱚᱶᱟ ᱧᱩᱛᱩᱢᱟᱜ ᱨᱮᱫ ᱵᱟᱹᱱᱩᱜ-ᱟ ᱾",
"upload-disallowed-here": "ᱟᱢᱫᱚ ᱱᱚᱣᱟ ᱨᱮᱫ ᱪᱮᱛᱟᱱ ᱵᱟᱢ ᱚᱞ ᱫᱟᱲᱮᱭᱟᱜ-ᱟ᱾",
+ "filerevert-comment": "ᱚᱡᱮ:",
"mimesearch": "MIME ᱥᱮᱸᱫᱽᱨᱟ",
"randompage": "ᱡᱚᱲᱟᱣ ᱥᱟᱦᱴᱟ",
"statistics": "ᱦᱟᱞᱚᱛ",
"prefixindex": "ᱡᱚᱛᱚ ᱥᱟᱦᱴᱟᱠᱚ prefix ᱥᱟᱶ",
"shortpages": "ᱦᱩᱰᱤᱧ ᱥᱟᱦᱴᱟᱠᱚ",
"longpages": "ᱡᱤᱞᱤᱧ ᱥᱟᱦᱴᱟᱠᱚ",
+ "protectedpages-page": "ᱥᱟᱦᱴᱟ",
+ "protectedpages-reason": "ᱚᱡᱮ",
"listusers": "ᱵᱮᱵᱦᱟᱨᱤᱡ ᱛᱟᱹᱞᱠᱟᱹ",
"listusers-creationsort": "ᱛᱮᱭᱟᱨᱟᱠᱟᱱ ᱢᱟᱹᱦᱤᱛ ᱞᱮᱠᱟᱛᱮ ᱯᱟᱱᱛᱮ",
"usercreated": "{{GENDER:$3|ᱵᱮᱱᱟᱣᱠᱟᱱ}} $1 ᱢᱟᱹᱦᱤᱛᱨᱮ $2 ᱚᱠᱛᱚᱨᱮ",
"listusers-blocked": "(ᱮᱥᱮᱫ ᱜᱮᱭᱟ)",
"listgrouprights-group": "ᱜᱟᱶᱛᱟ",
"listgrouprights-rights": "ᱟᱹᱭᱫᱟᱹᱨᱤᱠᱚ",
- "listgrouprights-helppage": "ᱜᱚᱲᱚᱸ:ᱜᱟᱫᱮᱞ ᱟᱹᱭᱫᱟᱹᱨ",
+ "listgrouprights-helppage": "Help:ᱜᱟᱫᱮᱞ ᱟᱹᱭᱫᱟᱹᱨ",
"listgrouprights-members": "(ᱥᱚᱦᱮᱫᱠᱩᱣᱟᱜ ᱛᱟᱹᱞᱠᱟᱹ)",
"listgrouprights-addgroup-all": "ᱡᱚᱛᱚ ᱜᱟᱶᱛᱟᱠᱩ ᱥᱮᱞᱮᱫ ᱠᱩ ᱢᱮ",
"listgrouprights-removegroup-all": "ᱡᱚᱛᱚ ᱜᱟᱶᱛᱟᱠᱩ ᱚᱪᱚᱜ ᱠᱩ ᱢᱮ",
"undeletelink": "ᱧᱮᱞ/ᱫᱚᱦᱚ ᱨᱩᱣᱟᱹᱲ",
"undeleteviewlink": "ᱧᱮᱞ",
"undelete-search-submit": "ᱥᱮᱸᱫᱽᱨᱟ",
+ "undelete-show-file-submit": "ᱦᱮᱸ",
"namespace": "ᱧᱤᱛᱩᱢ ᱡᱟᱜᱟ",
"invert": "ᱥᱮᱪ ᱵᱟᱪᱷᱟᱣ",
"tooltip-invert": "ᱱᱚᱶᱟ ᱵᱟᱠᱥᱟ ᱴᱤᱠ ᱢᱮ ᱥᱟᱦᱴᱟ ᱠᱷᱚᱱ ᱵᱚᱫᱚᱞᱟᱜᱠᱚ ᱫᱟᱱᱟᱝ ᱞᱟᱹᱜᱤᱫ ᱵᱟᱛᱷᱚᱱ ᱨᱟᱠᱷᱟ ᱧᱩᱛᱩᱢ ᱥᱟᱶᱛᱮ (ᱟᱨ ᱡᱚᱯᱚᱲᱟᱣᱟᱱ ᱨᱟᱠᱷᱟ ᱧᱩᱛᱩᱢ ᱡᱩᱫᱤ ᱴᱤᱠ ᱟᱠᱟᱱᱟ)",
"allmessagesname": "ᱧᱩᱛᱩᱢ",
"allmessagesdefault": "Bań bhul mesag ol",
"allmessages-filter-all": "ᱡᱚᱛᱚ",
+ "allmessages-language": "ᱯᱟᱹᱨᱥᱤ:",
"allmessages-filter-submit": "ᱪᱟᱞᱟᱜ ᱢᱮ",
+ "allmessages-filter-translate": "ᱛᱚᱨᱡᱚᱢᱟ",
"thumbnail-more": "ᱞᱟᱹᱴᱩᱭ ᱢᱮ",
"thumbnail_error": "Benawakan unuduḱ kạṭuṕ do baṅ ṭhika: $1",
"import-upload-filename": "ᱨᱮᱫᱧᱩᱛᱩᱢᱺ",
"pageinfo-toolboxlink": "ᱥᱦᱟᱴᱟ ᱨᱮᱭᱟᱜ ᱠᱷᱚᱵᱚᱨ",
"pageinfo-contentpage": "ᱩᱱᱩᱫᱩᱜ ᱥᱟᱦᱴᱟ ᱞᱮᱠᱟᱛᱮ ᱞᱮᱠᱷᱟ ᱦᱟᱠᱟᱱᱟ",
"pageinfo-contentpage-yes": "ᱦᱮᱸ",
+ "pageinfo-protect-cascading-yes": "ᱦᱮᱸ",
"patrol-log-page": "ᱛᱩᱱᱠᱷᱤᱭᱤᱡᱟᱜ ᱞᱚᱜᱽ",
"previousdiff": "← ᱢᱟᱨᱮᱱᱟᱜ ᱥᱟᱯᱲᱟᱣ",
"nextdiff": "ᱱᱟᱣᱟᱱᱟᱜ ᱥᱟᱯᱲᱟᱣ →",
"exif-subsectime": "ᱢᱟᱹᱦᱤᱛ ᱚᱠᱛᱚ ᱴᱤᱯᱤᱡ",
"exif-exposuretime-format": "$1 ᱴᱤᱯᱤᱡ ($2)",
"exif-gpsdatestamp": "GPS ᱢᱟᱹᱦᱤᱛ",
+ "exif-languagecode": "ᱯᱟᱹᱨᱥᱤ",
"exif-unknowndate": "ᱚᱪᱤᱱᱦᱟᱹᱣ ᱢᱟᱹᱦᱤᱛ",
"exif-orientation-1": "ᱥᱟᱫᱷᱟᱨᱚᱱ",
+ "exif-contrast-0": "ᱱᱚᱨᱢᱟᱞ",
+ "exif-saturation-0": "ᱱᱚᱨᱢᱟᱞ",
+ "exif-sharpness-0": "ᱱᱚᱨᱢᱟᱞ",
"exif-dc-date": "ᱢᱟᱹᱦᱤᱛ",
+ "exif-urgency-normal": "ᱱᱚᱨᱢᱟᱞ ($1)",
"namespacesall": "ᱡᱚᱛᱚ",
"monthsall": "ᱡᱚᱛᱚ",
"quotation-marks": "\"$1\"",
"tags-hitcount": "$1 {{PLURAL:$1|ᱟᱹᱨᱩ|ᱟᱹᱨᱩᱠᱚ}}",
"compare-page1": "ᱥᱟᱦᱴᱟ ᱑",
"compare-rev1": "ᱧᱮᱞᱟᱹᱨᱩ ᱑",
+ "htmlform-no": "ᱵᱟᱝ",
+ "htmlform-yes": "ᱦᱮᱸ",
"logentry-delete-delete": "$3 ᱥᱟᱦᱴᱟ $1 {{GENDER:$2|ᱜᱮᱫ ᱠᱮᱜ-ᱟᱭ}}",
"logentry-delete-restore": "$1 {{GENDER:$2|ᱨᱟᱠᱷᱟ ᱫᱚᱲᱦᱟ}} ᱠᱮᱜ-ᱟ ᱥᱟᱦᱴᱟ $3 ($4)",
"logentry-delete-revision": "$1 {{GENDER:$2|ᱵᱚᱫᱚᱞᱠᱮᱜ-ᱟᱭ}} ᱧᱮᱞᱚᱜᱟᱜ {{PLURAL:$5|ᱫᱚᱦᱲᱟᱭᱮᱱᱟᱜ|$5 ᱫᱚᱦᱲᱟᱭᱮᱱᱟᱜ ᱠᱚ}} $3: $4 ᱥᱟᱦᱴᱟ ᱪᱮᱛᱟᱱᱨᱮ",
"logentry-upload-overwrite": "$1 {{GENDER:$2|ᱞᱟᱫᱮᱭᱮᱱᱟ}} ᱢᱤᱫ ᱱᱟᱶᱟ ᱵᱷᱟᱨᱥᱚᱱ $3 ᱨᱮᱱᱟᱜ",
"searchsuggest-search": "ᱥᱮᱸᱫᱽᱨᱟ {{SITENAME}}",
"duration-days": "$1 {{PLURAL:$1|ᱢᱟᱦᱟᱸ|ᱢᱟᱸᱦᱟᱸ}}",
+ "pagelanguage": "ᱥᱟᱦᱴᱟ ᱯᱟᱹᱨᱥᱤ ᱵᱚᱫᱚᱞ",
+ "pagelang-language": "ᱯᱟᱹᱨᱥᱤ",
+ "right-pagelang": "ᱥᱟᱦᱴᱟ ᱯᱟᱹᱨᱥᱤ ᱵᱚᱫᱚᱞ",
"mw-widgets-dateinput-no-date": "ᱢᱟᱹᱦᱤᱛ ᱵᱟᱝ ᱵᱟᱪᱷᱚᱱ ᱟᱠᱟᱱᱟ",
"mw-widgets-mediasearch-input-placeholder": "ᱥᱮᱸᱫᱽᱨᱟᱭ ᱢᱮ ᱢᱮᱰᱤᱭᱟ",
"date-range-from": "ᱢᱟᱹᱦᱤᱛ ᱠᱷᱚᱱ:",
"redirectedfrom": "(Reindiritzadu dae $1)",
"redirectpagesub": "Pàgina de reindiritzamentu",
"redirectto": "Reindiritzat a:",
- "lastmodifiedat": "Ùrtimu càmbiu su $1, a is $2.",
+ "lastmodifiedat": "Ùrtima modìfica su $1, a is $2.",
"viewcount": "Custu artìculu l'ant lèghidu {{PLURAL:$1|borta|$1 bortas}}.",
"protectedpage": "Pàgina amparada",
"jumpto": "Bae a:",
"linkstoimage-redirect": "$1 (reindiritzamentu file) $2",
"sharedupload": "Custu file benit dae $1 e podet èssere impreadu in àteros progetos.",
"sharedupload-desc-here": "Custu documentu benit dae $1 e podet èssere impreadu in àteros progetos.\nA sighire est ammustrada sa descritzione in sa sua [$2 pàgina de descritzione de su documentu].",
+ "filepage-nofile": "Non b'at perunu documentu cun custu nùmene.",
"uploadnewversion-linktext": "Carriga una versione noa de custu file",
"shared-repo-from": "dae $1",
"filerevert-comment": "Motivu:",
"booksources": "Fontes libràrias",
"booksources-search-legend": "Chirca fontes libràrias",
"booksources-isbn": "ISBN:",
+ "booksources-search": "Chirca",
"specialloguserlabel": "Atzione fata dae:",
"speciallogtitlelabel": "Atzione fata subra:",
"log": "Registros",
"watchlist-options": "Optziones subra sa lista de pàginas annotadas",
"watching": "Giunghende a sa watchlist...",
"unwatching": "Boghende dae sa watchlist...",
+ "enotif_reset": "Marca totu sas pàginas bisitadas",
"enotif_impersonal_salutation": "Impitadore de {{SITENAME}}",
"enotif_anon_editor": "impitadore anònimu $1",
"created": "creada",
"contributions": "Cuntributos {{GENDER:$1|utente}}",
"contributions-title": "Contributziones de $1",
"mycontris": "Contributos mios",
+ "anoncontribs": "Contributziones",
"contribsub2": "Pro {{GENDER:$3|$1}} ($2)",
"nocontribs": "Nessuna modifica trovata conformemente a questi criteri.",
"uctop": "(atuale)",
"importstart": "Importande is pàginas...",
"import-revision-count": "$1 {{PLURAL:$1|revisione|revisiones}}",
"importlogpage": "Importatziones",
- "tooltip-pt-userpage": "Sa pàgina utente tua",
+ "tooltip-pt-userpage": "Sa pàgina impitadore {{GENDER:|tua}}",
"tooltip-pt-mytalk": "Sa pàgina de is cuntierras tuas",
- "tooltip-pt-preferences": "Is preferèntzias chi podes seberare",
+ "tooltip-pt-preferences": "Is preferèntzias {{GENDER:|tuas}}",
"tooltip-pt-watchlist": "Lista de is pàginas annotadas dae tue pro is mudàntzias",
"tooltip-pt-mycontris": "Sa lista de is contributos mios",
"tooltip-pt-login": "Sa registratzione est cussigiada; mancari chi non siat obligatoria",
"tooltip-feed-rss": "RSS feed pro custa pàgina",
"tooltip-feed-atom": "Atom feed pro custa pàgina",
"tooltip-t-contributions": "Càstia sa lista de is cuntributos de custu utente",
- "tooltip-t-emailuser": "Ispedi una email a custu impitadore",
+ "tooltip-t-emailuser": "Imbia una e-lìtera a {{GENDER:$1|custu impreadore}}",
"tooltip-t-upload": "Càrriga documentu multimediale",
"tooltip-t-specialpages": "Lista de is pàginas ispetziales",
"tooltip-t-print": "Versione de custa pàgina pro s'imprenta",
"tooltip-t-permalink": "Ligàmene permanente a custa versione de sa pàgina",
"tooltip-ca-nstab-main": "Càstia su cuntenutu de sa pàgina",
"tooltip-ca-nstab-user": "Càstia sa pàgina utente",
- "tooltip-ca-nstab-special": "Custa est una pàgina ispetziale, non si podet modificare",
+ "tooltip-ca-nstab-special": "Custa est una pàgina ispetziale, non podet èssere modificada",
"tooltip-ca-nstab-project": "Càstia sa pàgina de servìtziu",
"tooltip-ca-nstab-image": "Càstia sa pàgina de su file",
"tooltip-ca-nstab-template": "Càstia su template",
"file-nohires": "Non si tenent risolutziones prus artas.",
"svg-long-desc": "file in formadu SVG, mannesa nominale $1 × $2 pixel, mannesa de su file: $3",
"show-big-image": "Versione a risolutzione arta",
+ "show-big-image-size": "$1 × $2 pixels",
"imagelisttext": "Innoe sighendi du est una lista de '''$1''' {{PLURAL:$1|file|files}} ordinada $2.",
"newimages-legend": "Filtru",
"ilsubmit": "Chirca",
"metadata-expand": "Ammustra particulares",
"metadata-collapse": "Cua particulares",
"metadata-fields": "Is campos de is metadatos de imàgine listados in custu messàgiu ant a èssere ammustrados in sa pàgina de s'immàgine candu sa tabella de is metadatos est presentada in forma breve. Pro impostatzione predefinida, is àteros campos ant a èssere cuaos.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+ "exif-orientation": "Orientamentu",
"exif-artist": "Autore",
"exif-exposuretime-format": "$1 s ($2)",
"exif-fnumber-format": "f/$1",
"version-software-version": "Versione",
"version-entrypoints-header-url": "URL",
"redirect-submit": "Bae",
+ "redirect-value": "Valore:",
"redirect-user": "ID impitadore",
"redirect-page": "ID pàgina",
+ "redirect-revision": "Versione de sa pàgina",
+ "redirect-file": "Nùmene documentu",
"fileduplicatesearch-submit": "Chirca",
"specialpages": "Pàginas ispetziales",
"specialpages-note-top": "Legenda",
"feedback-close": "Fatu",
"feedback-message": "Messàgiu:",
"feedback-subject": "Ogetu:",
- "searchsuggest-search": "Chirca",
+ "searchsuggest-search": "Chirca in intro de {{SITENAME}}",
"expand_templates_ok": "OK",
"expand_templates_preview": "Antiprima",
"pagelang-name": "Pàgina",
"copyrightwarning": "ياد رکندا ته {{SITENAME}} لاءِ سموريون ڀاڱيداريون $2 تحت پڌريون ڪجن ٿيون (تفصيلن لاءِ $1 ڏسندا). اوهان جي تحرير کي {{SITENAME}} جي قائدن تحت ترميمي سگهجي ٿو. جيڪڏهن اوهان نه ٿا چاهيو ته اوهان جي لکڻين کي بي رحميءَ سان ترميميو وڃي يا ورهائي عام ڪيو وڃي ته پوءِ پنهنجي لکڻي هتي جمع نه ڪرايو. پنهنجو مواد هتي جمع ڪرڻ جو مطلب هوندو ته توهان کي جمع ڪرايل مواد جي مفت فراهمي ۽ کُليل تبديليءَ تي ڪو به اعتراز ناهي.<br />\nتوهان اهڙي پڪ ڏيڻ جا پابند پڻ آهيو ته توهان جو جمع ڪرايل مواد توهان جو پنهنجو لکيل آهي يا وري توهان ڪنهن مفت وسيلي تان ڪاپي ڪيو آهي.\n'''تحفظيل حق ۽ واسطا رکندڙ مواد واسطيدار مالڪ کان اڳواٽ اجازت وٺڻ کان سواءِ هتي جمع نه ڪريو.'''",
"copyrightwarning2": "ياد رکندا تہ {{SITENAME}} لاءِ سموريون ڀاڱيدارين کي ٻيا ڀاڱيدار سنواري، بدلائي، يا ڊاهي سگھن ٿا. جيڪڏهن اوهان نہ ٿا چاهيو تہ اوهان جي لکڻين کي بي رحميءَ سان ترميميو وڃي يا ورهائي عام ڪيو وڃي تہ پوءِ پنهنجي لکڻي هتي جمع نہ ڪرايو.</br>\nتوهان اهڙي پڪ ڏيڻ جا پابند پڻ آهيو تہ توهان جو جمع ڪرايل مواد توهان جو پنهنجو لکيل آهي يا وري توهان ڪنهن اهڙي ئي مفت عوامي وسيلي تان ڪاپي ڪيو آهي. (تفصيلن لاءِ $1 ڏسندا).\n\n<strong>تحفظيل حق ۽ واسطا رکندڙ مواد واسطيدار مالڪ کان اڳواٽ اجازت وٺڻ بنان هتي جمع نہ ڪريو.</strong>",
"protectedpagewarning": "<strong>چتاءُ: هيءَ صفحو اهڙيءَ ريت تحفظيو ويو آهي جو فقط منتظمين ئي ان کي سنواري سگھن ٿا. </strong>\nتازه ترين لاگ حوالي طور پيش ڪجي ٿو:",
- "semiprotectedpagewarning": "<strong>نوٽ:</strong> هيءَ صفحو اهڙيءَ ريت تحفظيو ويو آهي جو فقط کاتيدار واپرائيندڙ ئي ان کي سنواري سگھن ٿا.\nتازه ترين لاگ حوالي طور پيش ڪجي ٿو:",
+ "semiprotectedpagewarning": "<strong>نوٽ:</strong> هيءَ صفحو اهڙيءَ ريت تحفظيو ويو آهي جو فقط خودڪار نموني پڪ ڪيل واپرائيندڙ ئي ان کي سنواري سگھن ٿا.\nتازه ترين لاگ حوالي طور پيش ڪجي ٿو:",
"templatesused": "هن صفحي تي استعمال ٿيندڙ {{PLURAL:$1|سانچو|سانچا}}:",
"templatesusedpreview": "هن پيش نگاھ ۾ استعمال ٿيل {{PLURAL:$1|سانچو|سانچا}}:",
"templatesusedsection": "هن سيڪشن ۾ استعمال ٿيل {{PLURAL:$1|سانچو|سانچا}}:",
"recentchangesdays": "تازين تبديلين ۾ ڏيکارڻ جي لاءِ ڏينهن:",
"recentchangesdays-max": "وڌ ۾ وڌ $1 {{PLURAL:$1|ڏينهن}}",
"recentchangescount": "عدم پيروي جي صورت ۾ ڏيکارڻ جي لاءِ ترميمون:",
- "prefs-help-recentchangescount": "ان ۾ تازيون تبديليون، صفحن جي سوانح، ۽ لاگ شامل آهن.",
+ "prefs-help-recentchangescount": "وڌ ۾ وڌ انگ: 1000",
"savedprefs": "توھان جون ترجيحون سانڍجي چڪيون آھن.",
"savedrights": "{{GENDER:$1|$1}} جا واپرائيندڙ گروھ سانڍجي چڪا آھن.",
"timezonelegend": "اوقاتي زون:",
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "Vikoula5"
+ ]
+ },
+ "tog-underline": "Aderrer n iseɣwan:",
+ "tog-hideminor": "Ffer ibeddilen ifessasen deg yibeddilen imaynuten",
+ "tog-hidepatrolled": "Ffer ibeddilen yettwaɣran deg yibeddilen imaynuten",
+ "tog-newpageshidepatrolled": "Ffer isebtar yettwaɣran deg tebdart n isebtar imaynten",
+ "tog-hidecategorization": "Ffer taggayin n isebtar",
+ "tog-extendwatchlist": "Ssemɣer umuɣ n uɛessi iwakken ad muqleɣ akk n wayen zemreɣ ad beddleɣ",
+ "tog-usenewrc": "Ssegrew ibeddlen s usebtar deg ibeddilen imaynuten d umuɣ n uḍfar",
+ "tog-numberheadings": "Izwal ɣur-sen imḍanen mebla ma serseɣ-iten",
+ "tog-showtoolbar": "Ssken tafeggagt n ifecka n ubeddel",
+ "tog-editondblclick": "Beddel isebtar mi wekkiɣ snat n tikwal",
+ "tog-editsectiononrightclick": "Ssermed abeddel n tigezmi s ukliki ayeffus ɣef izwal",
+ "tog-watchcreations": "Rnu isebtar i xelqeɣ deg wumuɣ n uɛessi inu",
+ "tog-watchdefault": "Rnu isebtar i ttbeddileɣ deg wumuɣ n uɛessi inu",
+ "tog-watchmoves": "Rnu isebtar i smimḍeɣ deg wumuɣ n uɛessi inu",
+ "tog-watchdeletion": "Rnu isebtar i mḥiɣ deg wumuɣ n uɛessi inu",
+ "tog-watchuploads": "Rnu ifuyla imaynuten i suliɣ ar tebdart-iw n uqreɛ",
+ "tog-watchrollback": "Rnu ar tebdart-iw n uḍfaṛ n isebtar anida hwiɣ albaɛd",
+ "tog-minordefault": "Rcem akk ibeddlen am ibeddlen ifessasen d ameslugen",
+ "tog-previewontop": "Ssken pre-timeẓriwt uqbel tankult ubeddel",
+ "tog-previewonfirst": "Ssken pre-timeẓriwt akk d ubeddel amezwaru",
+ "tog-enotifwatchlistpages": "Azen-iyi-d e-mail m'ara yettubeddel asebter i ttɛassaɣ",
+ "tog-enotifusertalkpages": "Azen-iyi-d e-mail asmi sɛiɣ izen amaynut",
+ "tog-enotifminoredits": "Azen-iyi-d e-mail ma llan ibeddlen ifessasen",
+ "tog-enotifrevealaddr": "Ssken e-mail inu asmi yettwazen email n talɣut",
+ "tog-shownumberswatching": "Ssken geddac yellan n yimseqdacen iɛessasen",
+ "tog-oldsig": "Azmul-ik yellan :",
+ "tog-fancysig": "Eǧǧ azmul am yettili (war azday awurman)",
+ "tog-uselivepreview": "Sken tiskanin s war asmiren n usebter",
+ "tog-forceeditsummary": "Ini-iyi-d mi sskecmeɣ agzul amecluc",
+ "tog-watchlisthideown": "Ffer ibeddlen inu seg wumuɣ n uɛessi inu",
+ "tog-watchlisthidebots": "Ffer ibeddlen n iboṭiyen seg wumuɣ n uɛessi inu",
+ "tog-watchlisthideminor": "Ffer ibeddlen ifessasen seg wumuɣ n uɛessi inu",
+ "tog-watchlisthideliu": "Ffer ibeddlen n iseqdacen yelan deg umuɣ n tiḍefri",
+ "tog-watchlistreloadautomatically": "Ales asali s wudem awurman n tebdart n uḍfaṛ ticki iɣewwaṛen n usizdeg ttwabeddlen (Ilaq JavaScript)",
+ "tog-watchlistunwatchlinks": "Rnu iseɣwan srid n uḍfaṛ/aseḥbes ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}) n uḍfaṛ i yinekcam n tebdart n uḍfaṛ(Ilaq JavaScript i usefrek n tmahilt-agi)",
+ "tog-watchlisthideanons": "Ffer ibeddlen n iseqdacen udrigen deg umuɣ n tiḍefri",
+ "tog-watchlisthidepatrolled": "Ffer ibeddlen iɛessan deg umuɣ n tiḍefri",
+ "tog-watchlisthidecategorization": "Ffer taggayin n isebtar",
+ "tog-ccmeonemails": "Azen-iyi-d email n wayen uzneɣ i imseqdacen wiyaḍ",
+ "tog-diffonly": "Ur temliḍ-iyi-d ara ayen yellan seddaw imgerraden",
+ "tog-showhiddencats": "Beqqeḍ taggayin yeffren",
+ "tog-norollbackdiff": "Ur skan ara amgired seld aḥway",
+ "tog-useeditwarning": "Σeggen iyid mi ara fγaγ seg usebter mebla ma skeslaγ ibeddilen.",
+ "tog-prefershttps": "Seqdac yal tikelt tuqqna taɣelsant akken ad teqqneḍ",
+ "underline-always": "Yal tikelt",
+ "underline-never": "Werǧin",
+ "underline-default": "Azal s lexṣas n iminig neɣ n usentel",
+ "editfont-style": "Aɣanib n tasefsit n taɣzut ubeqqeḍ",
+ "editfont-monospace": "Tasefsit s lqedd usbiḍ",
+ "editfont-sansserif": "Tasefsit \"Sans-serif\"",
+ "editfont-serif": "Tasefsit \"Serif\"",
+ "sunday": "Acer",
+ "monday": "Arim",
+ "tuesday": "Aram",
+ "wednesday": "Ahad",
+ "thursday": "Amhad",
+ "friday": "Sem",
+ "saturday": "Sed",
+ "sun": "Ace.",
+ "mon": "Ari.",
+ "tue": "Ara.",
+ "wed": "Aha.",
+ "thu": "Amh.",
+ "fri": "Sem",
+ "sat": "Sed",
+ "january": "Yannayer",
+ "february": "Furar",
+ "march": "Meɣres",
+ "april": "Brir",
+ "may_long": "Mayu",
+ "june": "Yunyu",
+ "july": "Yulyez",
+ "august": "Ɣuct",
+ "september": "Ctember",
+ "october": "Kuber",
+ "november": "Wember",
+ "december": "Jember",
+ "january-gen": "Yannayer",
+ "february-gen": "Furar",
+ "march-gen": "Meɣres",
+ "april-gen": "Brir",
+ "may-gen": "Mayu",
+ "june-gen": "Yunyu",
+ "july-gen": "Yulyez",
+ "august-gen": "Ɣuct",
+ "september-gen": "Ctember",
+ "october-gen": "Kuber",
+ "november-gen": "Wember",
+ "december-gen": "Jember",
+ "jan": "Yan",
+ "feb": "Fur",
+ "mar": "Meɣ",
+ "apr": "Bri",
+ "may": "May",
+ "jun": "Yun",
+ "jul": "Yul",
+ "aug": "Ɣuc",
+ "sep": "Cte",
+ "oct": "Kub",
+ "nov": "Wem",
+ "dec": "Jem",
+ "january-date": "Yannayer $1",
+ "february-date": "Furar $1",
+ "march-date": "Meɣres $1",
+ "april-date": "Brir $1",
+ "may-date": "Mayu $1",
+ "june-date": "Yunyu $1",
+ "july-date": "Yulyez $1",
+ "august-date": "Ɣuct $1",
+ "september-date": "Ctember $1",
+ "october-date": "Kuber $1",
+ "november-date": "Wember $1",
+ "december-date": "Jember $1",
+ "period-am": "FT",
+ "period-pm": "MD",
+ "pagecategories": "{{PLURAL:$1|Taggayt|Taggayin}}",
+ "category_header": "Isebtar deg taggayt \"$1\"",
+ "subcategories": "Adutaggayin",
+ "category-media-header": "Media deg taggayt \"$1\"",
+ "category-empty": "<em>Taggayt agi ur tesɛa asebtar, adu-taggayt neɣ afaylu agetmedia.</em>",
+ "hidden-categories": "{{PLURAL:$1|Taggayt yeffren|Taggayin yeffren}}",
+ "hidden-category-category": "Taggayin yeffren",
+ "category-subcat-count": "Taggayt-agi {{PLURAL:$2|0=ur tegbir ula d yiwet n taggayt tasnawt|1=tegber kan taggayt tasnawant ddaw-a|tegber $2 n taggayin tisnawanin, gar-asent {{PLURAL:$1|0=ula d yiwet|1=tin|tigad $1}} ddaw-a}}.",
+ "category-subcat-count-limited": "Taggayt-agi tegber {{PLURAL:$1|n taggayt tasnawant|$1 n taggayin tisnawanin}} ddaw-a.",
+ "category-article-count": "Taggayt-agi{{PLURAL:$2|0=ur tegbur ula d yiwen n usebtert|1=tegber kan yiwen n usebterddaw-a|tegber $2 n isebtar, gar-asen {{PLURAL:$1|0=ula d yiwen|1=tin| $1}} n ddaw-a}}.",
+ "category-article-count-limited": "{{PLURAL:$1|Asebter agi yella|$1 isebtar agi llan}} deg taggayt agi.",
+ "category-file-count": "Taggayt agi tesɛa {{PLURAL:$2|afaylu agi|$2 ifuyla, ɣef ayed {{PLURAL:$1|t-agi|t-igi $1}} ddaw-agi}}.",
+ "category-file-count-limited": "{{PLURAL:$1|Afaylu agi yella|$1 ifuyla agi llan}} deg taggayt agi.",
+ "listingcontinuesabbrev": "asartu",
+ "index-category": "Isebtar s umatar",
+ "noindex-category": "Asebter-agi ur ɣur-s ara amatar",
+ "broken-file-category": "Isebtar s iseɣwan n ifuyla iṛzan",
+ "about": "Awal ɣef...",
+ "article": "Ayen yella deg usebter",
+ "newwindow": "(ad d-yeldi deg usfaylu amaynut)",
+ "cancel": "Eǧǧ-it am yella",
+ "moredotdotdot": "Ugar...",
+ "morenotlisted": "Tabdart-agi ur temmid ara",
+ "mypage": "Asebter",
+ "mytalk": "Asqerdec",
+ "anontalk": "Asqerdec",
+ "navigation": "Assilel",
+ "and": " akked",
+ "faq": "Isteqsiyen FAQ",
+ "actions": "Tigawtin",
+ "namespaces": "Talluntin n isemawen",
+ "variants": "Tineḍwa",
+ "navigation-heading": "Umuɣ n tunigin",
+ "errorpagetitle": "Agul",
+ "returnto": "Uɣal ar $1.",
+ "tagline": "Seg {{SITENAME}}",
+ "help": "Tallalt",
+ "search": "Iruzzi",
+ "search-ignored-headings": "#<!-- eǧǧ izirigen-agi akken llan --><pre>\n# Izwal n tgezmiyin ad ttwazeglen deg unadi\n# Ibeddilen yettwagen dagi ad ddun ticki asebter s uzwel yettwarna ar umatar.\n# Tzemreḍ ad ḥettmeḍ tulsa n tmerna ar umatar n usebter s usnifel ilem\n# Taseddast d tagi :\n# * Yal iziirig ibeddun s \"#\" d awennit\n# * Yal izirig yeččuren d azwel ara tzegleḍ, ula d taṛuzi n usekkil\nTimsisɣal\nIseɣwan izɣarayen\nWali daɣen\n #</pre><!-- eǧǧ izirig-agi akken yella -->",
+ "searchbutton": "Iruzzi",
+ "go": "Ẓer",
+ "searcharticle": "Ẓer",
+ "history": "Amezruy n usebter",
+ "history_short": "Amazray",
+ "history_small": "amazray",
+ "updatedmarker": "yettubeddel segmi tarzeft taneggarut inu",
+ "printableversion": "Lqem n usiggez",
+ "permalink": "Azday ur yettbeddil ara",
+ "print": "Siggez",
+ "view": "Ɣeṛ",
+ "view-foreign": "Sken di $1",
+ "edit": "Glef",
+ "edit-local": "Rnu aglam adigan",
+ "create": "Snulfu",
+ "create-local": "Rnu aglam n adigan",
+ "delete": "Mḥu",
+ "undelete_short": "Fakk amḥay n {{PLURAL:$1|yiwen ubeddel|$1 yibeddlen}}",
+ "viewdeleted_short": "Ẓeṛ {{PLURAL:$1|yiwen abeddel yettumḥan|$1 Ibeddlen yettumḥan}}",
+ "protect": "Ḥrez",
+ "protect_change": "beddel tiḥḥerzi",
+ "unprotect": "Beddel amesten",
+ "newpage": "Asebter amaynut",
+ "talkpagelinktext": "Mmeslay",
+ "specialpage": "Asebter uslig",
+ "personaltools": "Dduzan inu",
+ "talk": "Asqerdec",
+ "views": "Tuẓrin",
+ "toolbox": "Ifecka",
+ "tool-link-userrights": "Snifel igrawen n {{GENDER:$1|useqdac}}",
+ "tool-link-userrights-readonly": "Sken igrawen n {{GENDER:$1|useqdac}}",
+ "tool-link-emailuser": "Azen emayl i {{GENDER:$1|useqdac}}",
+ "imagepage": "Ẓer asebter n tugna",
+ "mediawikipage": "Ẓer asebter n izen",
+ "templatepage": "Ẓer asebter n talɣa",
+ "viewhelppage": "Ẓer asebter n tallalt",
+ "categorypage": "Ẓer asebter n taggayin",
+ "viewtalkpage": "Wali asqerdec",
+ "otherlanguages": "S tutlayin tiyaḍ",
+ "redirectedfrom": "(Yettusmimeḍ seg $1)",
+ "redirectpagesub": "Asebter usemmimeḍ",
+ "redirectto": "Welleh ar:",
+ "lastmodifiedat": "Asebter-agi ibeddel i tikelt taneggarut di $2, $1.",
+ "viewcount": "Asebter-agi yettwakcem {{PLURAL:$1|yiwet tikelt|$1 tikwal}}.",
+ "protectedpage": "Asebter yettwaḥerzen",
+ "jumpto": "Neggez ar:",
+ "jumptonavigation": "ẓer isebtar",
+ "jumptosearch": "iruzzi",
+ "view-pool-error": "Suref-aɣ, iqeddacen iwziren tura.\nAṭas iseqdacen tnadin ad ẓṛen asebter agi.\nIlaq ad arǧuḍ imir uqbel ad εreḍeḍ tikkelt nniḍen .\n\n$1",
+ "generic-pool-error": "Suref-aɣ, iqeddacen ur stufan ara akka tura.\nDdeqs n iseqdacen ttnadin ad ẓṛen taɣbalut-agi.\nMa ulac aɣilif, rǧu cwiṭ send ad tεreḍeḍ ad tkecmeḍ tikkelt-nniḍen.",
+ "pool-timeout": "Amenḍar iɛedda deg taganit n uzekṛun",
+ "pool-queuefull": "Adras n umahil yečuṛ",
+ "pool-errorunknown": "Tuccḍa tarussint",
+ "pool-servererror": "Amẓlu n uḥerri ur iheegi ara ($1)",
+ "poolcounter-usage-error": "Tuccḍa n useqdec: $1",
+ "aboutsite": "Ɣef {{SITENAME}}",
+ "aboutpage": "Project:Ɣef",
+ "copyright": "Agbur yella ddaw $1 ḥaca ma abdar anemgal.",
+ "copyrightpage": "{{ns:project}}:Copyrights",
+ "currentevents": "Isallen",
+ "currentevents-url": "Project:Isallen",
+ "disclaimers": "Ilɣa",
+ "disclaimerpage": "Project:Ilɣa imuta",
+ "edithelp": "Tallelt ɣef teẓrigt",
+ "helppage-top-gethelp": "Tallelt",
+ "mainpage": "Amzawru Tasfhit",
+ "mainpage-description": "Amzawru Tasfhit",
+ "policy-url": "Project:Ilugan",
+ "portal": "Awwur n timetti",
+ "portal-url": "Project:Awwur n timetti",
+ "privacy": "Tasertit n tbaḍnit",
+ "privacypage": "Project:Tasertit n tbaḍnit",
+ "badaccess": "Agul n turagt",
+ "badaccess-group0": "Ur tettalaseḍ ara ad texedmeḍ tigawt i tseqsiḍ.",
+ "badaccess-groups": "Tigawt id steqsiḍ t-uffar kan i iseqdacen n {{PLURAL:$2|ugraw|igrawen}} : $1.",
+ "versionrequired": "Yessefk ad tesɛiḍ tasiwelt $1 n MediaWiki",
+ "versionrequiredtext": "Yessefk ad tesɛiḍ tasiwelt $1 n MediaWiki iwakken ad tesseqdceḍ asebter-agi. Ẓer [[Special:Version|tasiwelt n usebter]].",
+ "ok": "Seɣbel",
+ "retrievedfrom": "Yettwaddem seg \"$1\"",
+ "youhavenewmessages": "{{PLURAL:$3|Ɣur-k}} $1 ($2).",
+ "youhavenewmessagesfromusers": "{{PLURAL:$4|Tesɛiḍ}} $1 n {{PLURAL:$3|useqdac nniḍen|$3 iseqdacen nniḍen}} ( $2 ).",
+ "youhavenewmessagesmanyusers": "Tesɛiḍ $1 n aṭas n iseqdacen ($2).",
+ "newmessageslinkplural": "{{PLURAL:$1|izen amaynut|999=inzan imaynuten}}",
+ "newmessagesdifflinkplural": "{{PLURAL:$1|abeddel aneggaru|999=ibeddilen ineggura}}",
+ "youhavenewmessagesmulti": "Tesɛiḍ iznan imaynuten deg $1",
+ "editsection": "glef",
+ "editold": "glef",
+ "viewsourceold": "ẓeṛ aɣbalu",
+ "editlink": "glef",
+ "viewsourcelink": "ẓeṛ aɣbalu",
+ "editsectionhint": "Glef tagzemt: $1",
+ "toc": "Agbur",
+ "showtoc": "Ssken",
+ "hidetoc": "Ffer",
+ "collapsible-collapse": "Seggelmes",
+ "collapsible-expand": "Beqqeḍ",
+ "confirmable-confirm": "D tidett d {{GENDER:$1|kečč|kem}}?",
+ "confirmable-yes": "Ih",
+ "confirmable-no": "Uhu",
+ "thisisdeleted": "Ẓer neɣ err $1 am yella?",
+ "viewdeleted": "Ẓer $1?",
+ "restorelink": "{{PLURAL:$1|Yiwen abeddel yettumḥan|$1 Ibeddlen yettumḥan}}",
+ "feedlinks": "Asuddem:",
+ "feed-invalid": "Anaw n usuddem mačči ṣaḥiḥ.",
+ "feed-unavailable": "Isuddman RSS ur yestufan ara",
+ "site-rss-feed": "Asuddem RSS n $1",
+ "site-atom-feed": "Taneflit Atom n $1",
+ "page-rss-feed": "Asuddem RSS n \"$1\"",
+ "page-atom-feed": "Taneflit Atom n \"$1\"",
+ "red-link-title": "$1 (ulac asebter)",
+ "sort-descending": "Afran akaray",
+ "sort-ascending": "Afran aseffes",
+ "nstab-main": "Amagrad",
+ "nstab-user": "Asebter n wemseqdac",
+ "nstab-media": "Asebter n media",
+ "nstab-special": "Asebter uzzig",
+ "nstab-project": "Awal ɣef...",
+ "nstab-image": "Afaylu",
+ "nstab-mediawiki": "Izen",
+ "nstab-template": "Tamudemt",
+ "nstab-help": "Tallalt",
+ "nstab-category": "Taggayt",
+ "mainpage-nstab": "Asebter agejdan",
+ "nosuchaction": "Tigawt ulac-itt",
+ "nosuchactiontext": "Wiki ur teɛqil ara tigawt-nni n URL",
+ "nosuchspecialpage": "Asebter uslig am wagi ulac-it.",
+ "nospecialpagetext": "<strong>Tseqsiḍ ɣef usebter uslig ulac-it, tzemreḍ ad tafeḍ isebtar</strong>\nusligen n ṣṣeḥ deg [[Special:SpecialPages|wumuɣ n isebtar usligen]].",
+ "error": "Agul",
+ "databaseerror": "Agul n database",
+ "databaseerror-text": "Tuccḍa n tuttra deg taffa n isefka teḍra-d. Ahat yella afuqes deg useɣẓan.",
+ "databaseerror-textcl": "Tuccḍa n tuttra deg taffa n isefka teḍra-d",
+ "databaseerror-query": "Tuttra : $1",
+ "databaseerror-function": "Tuccḍa: $1",
+ "databaseerror-error": "Agul: $1",
+ "laggedslavemode": "<strong>Aɣtal:</strong> Ahat asebter ur yesɛi ara akk ibeddlen imaynuten.",
+ "readonly": "Database d tamsekkert",
+ "enterlockreason": "Ini ayɣer tsekkreḍ database, ini daɣen melmi ara ad ifukk asekker",
+ "readonlytext": "Taffa n isefka teskweṛ akka tura ɣef sebba n kra n inekcam d usnifel-nniḍen, ahat ɣef kra n uxeddim n uṣeggem, ticki ifuk ad tuɣal.\n\nAndbal n unagraw iṣekṛen taffa yenna-d acimi: $1",
+ "missing-article": "Taffa n isefka ur t-ufa ara aḍris n yiwen usebter ilaq at af, s-isem \"$1\"$2.\n\nUmata, wagi yeḍra mi neḍfeṛ azday ɣer yiwen diff aqbur naɣ ɣer amazray n usebter yemḥan.\n\nMa mačči d-tajṛut agi, ihi d-taniwit deg uhil.\nIlaq ad εeggenem yiwen [[Special:ListUsers/sysop|anedbal]] war ad ttum asefkem URL n uzday.",
+ "missingarticle-rev": "(uṭṭun n lqem#: $1)",
+ "missingarticle-diff": "(Diff: $1, $2)",
+ "readonly_lag": "Database d tamsekkert (weḥdes) axaṭer kra n serveur ɛeṭṭlen",
+ "internalerror": "Agul zdaxel",
+ "internalerror_info": "Anezri agensan : $1",
+ "filecopyerror": "Ur yezmir ara ad yexdem alsaru n ufaylu \"$1\" ar \"$2\".",
+ "filerenameerror": "Ur yezmir ara ad ibeddel isem ufaylu \"$1\" ar \"$2\".",
+ "filedeleteerror": "Ulamek an mḥu afaylu \"$1\".",
+ "directorycreateerror": "Ulamek an snulfu akaram \"$1\"",
+ "directoryreadonlyerror": "Akaram \"$1\" i tɣuri kan.",
+ "directorynotreadableerror": "Akaram \"$1\" ur yettwaɣray ara.",
+ "filenotfound": "Ur yezmir ara ad yaf afaylu \"$1\".",
+ "unexpected": "Agul: \"$1\"=\"$2\".",
+ "formerror": "Agul: ur yezmir ara ad yazen talɣa",
+ "badarticleerror": "Ur yezmir ara ad yexdem tigawt-agi deg usebter-agi.",
+ "cannotdelete": "Ulamek ad yemḥu asebter naɣ afaylu \"$1\".\nAhat amdan wayeḍ yemḥa-t.",
+ "cannotdelete-title": "Ulamek an kkes asebter \"$1\"",
+ "delete-hook-aborted": "Tukkesa tesemmet s usiɣzef.\nUlac asefru ɣef wagi.",
+ "no-null-revision": "Ur nezmer ara ad n-snulfu tacaggart tilemnt tamaynut i usebtar \"$1\"",
+ "badtitle": "Azwel ur yelhi",
+ "badtitletext": "Asebter i testeqsiḍ fell-as mačči ṣaḥiḥ, d ilem, neɣ yella ugul deg wezday seg wikipedia s tutlayt tayeḍ neɣ deg wezday n wiki nniḍen. Ahat tesɛa asekkil ur yezmir ara ad yettuseqdac deg wezwel.",
+ "title-invalid-empty": "Azwel n usebter d-tessutreḍ d ilem neɣ yegber kan isem n tallunt n yismawen.",
+ "title-invalid-utf8": "Azwel n usebter d-tessutreḍ yegber tagzemt UTF-8 taruɣbilt",
+ "title-invalid-talk-namespace": "Azwel n usebter d-tessutreḍ yettwellih ar usebter n usqerdec ay izemren ulac-it",
+ "title-invalid-characters": "Azwel n usebter d-tessutreḍ yegber isekkilen iruɣbilen: \"$1\".",
+ "perfcached": "Talɣut deg ukessar seg lkac u waqila mačči d tasiwelt taneggarut. A maximum of {{PLURAL:$1|one result is|$1 results are}} available in the cache.",
+ "perfcachedts": "Talɣut deg ukessar seg lkac, tasiwelt taneggarut n wass $1. A maximum of {{PLURAL:$4|one result is|$4 results are}} available in the cache.",
+ "querypage-no-updates": "Ibeddlen n usebter-agi ur ttbanen ara tura. Tilɣa ines qrib a d-banen.",
+ "viewsource": "Ẓer aɣbalu",
+ "viewsource-title": "Ẓeṛ aɣbalu n $1",
+ "actionthrottled": "Tigawt tesɛa talast",
+ "actionthrottledtext": "Akken ad nsiḥbiber mgal tuzna n ispamen, aseqdec n tigawt-agi tesɛa talast n umḍan n tikalt n wakud wezzilen kan ihi tɛeddaḍ talast.\nƐred tikelt-nniḍen di kra n tisdatin.",
+ "protectedpagetext": "Asebter-agi yetwaḥrez i uqareɛ n ubeddel neɣ tigawin nniḍen.",
+ "viewsourcetext": "Tzemreḍ ad twaliḍ u txedmeḍ alsaru n uɣbalu n usebter-agi:",
+ "viewyourtext": "Tzemṛeḍ ad ẓṛeḍ dɣa ad nɣeleḍ agbur n \"ibeddlen inek/inem\" deg usebter agi :",
+ "protectedinterface": "Asebter-agi d amsekker axaṭer yettuseqdac i weḍris n software.",
+ "editinginterface": "<strong>Ɣuṛ-k:</strong> Aqla-k tettbeddileḍ asebter yettuseqdacen i tmerna n uḍris n ugrudem n useɣẓan. \nIbeddilen ɣef usebter-agi ad ḥazen udem n ugrudem n useqdac i yiseqdacen-nniḍen n uwiki.",
+ "translateinterface": "Akken ad ternuḍ neɣ ad tbeddleḍ tisuqilin i yiwikiyen meṛṛa, seqdec [https://translatewiki.net/ translatewiki.net], asenfaṛ n usideg utlayan n MediaWiki.",
+ "cascadeprotected": "Asebter-agi yettwammesten mgal abeddel acku yedda deh {{PLURAL:$1|usebter d-iteddun yettwammestnen|isebtar-agi d-itedduun yettwammestnen}} s usefran \"ammesten s udabdar\" urmid:\n$2",
+ "namespaceprotected": "Ur tesɛiḍ ara turagt iwakken ad beddeleḍ isebtar n tallunt n isemawen <strong>$1</strong>.",
+ "customcssprotected": "Ur tesɛiḍ ara turagt iwakken ad beddeleḍ asebter agi n CSS, acku tesɛa iɣewwaren n yiwen useqdac nniḍen.",
+ "customjsprotected": "Ur tesɛiḍ ara turagt iwakken ad beddeleḍ asebter agi n Javascript, acku tesɛa iɣewwaren n yiwen useqdac nniḍen.",
+ "mycustomcssprotected": "Ur tesɛiḍ ara turagt i ubeddel n usebtar agi CSS.",
+ "mycustomjsonprotected": "Ur tesɛiḍ ara turagt i ubeddel n usebtar agi JSON.",
+ "mycustomjsprotected": "Ur tesɛiḍ ara turagt i ubeddel n usebtar agi JavaScript.",
+ "myprivateinfoprotected": "Ur tesɛiḍ ara turagt ad beddeleḍ tilɣa inek(em) tusligtin.",
+ "mypreferencesprotected": "Ur tesɛiḍ ara turagt ad beddeleḍ iɣewwaren inek(em).",
+ "ns-specialprotected": "Ur t-zemred ara ad beddeleḍ isebtar usligen",
+ "titleprotected": "Azwel agi yegdel deg usnulfu ɣef [[User:$1|$1]].\nTaɣẓint id yenna : <em>$2</em>",
+ "filereadonlyerror": "Ulamek ad nbeddel afaylu \"$1\" acku akaram n ifuyla \"$2\" yella deg uskar n tɣuri kan.\n\nAnedbal n unagraw i t-isekkweṛen, yefka-d asegzi-agi : \"$3\".",
+ "invalidtitle-knownnamespace": "Azwel ur i ɣbel ara s tallunt n isemawen « $2 » dɣa d-uglam « $3 »",
+ "invalidtitle-unknownnamespace": "Azwel ur i ɣbel ara s uṭṭun n tallunt n isemawen $1 dɣa d-uglam « $2 » warisem",
+ "exception-nologin": "Ur tekcimeḍ ara",
+ "exception-nologin-text": "Qqen akken ad tizmireḍ ad tkecmeḍ ar usebter-agineɣ tigawt-agi.",
+ "exception-nologin-text-manual": "$1 iwakken ad kecmeḍ ar asebtar neɣ tigawt agi.",
+ "virus-badscanner": "Yir tawila : anafraḍ n infafaden warisem : <em>$1</em>",
+ "virus-scanfailed": "Abrir n unadi (tangalt $1)",
+ "virus-unknownscanner": "amgelanfafad warisem :",
+ "logouttext": "<strong>Tura tesensereḍ.</strong>\n\nKra n isebtar zemren ad sskanen belli mazal-ik s yisem n wemseqdac inek armi temḥuḍ tazarkatut.",
+ "cannotlogoutnow-title": "Ur tezmireḍ ara ad teffɣeḍ tura",
+ "cannotlogoutnow-text": "Tuffɣa d tawezɣit ticki tseqdaceḍ $1.",
+ "welcomeuser": "Anṣuf, $1 !",
+ "welcomecreation-msg": "Amian inek(em) yesnulfad.\nTzemreḍ ad beddeleḍ {{SITENAME}} [[Special:Preferences|ismenyifen]] inek(em) ma tebɣiḍ",
+ "yourname": "Isem n useqdac:",
+ "userlogin-yourname": "Isem n useqdac",
+ "userlogin-yourname-ph": "Sekcem isem-ik(im) n useqdac",
+ "createacct-another-username-ph": "Sekcem isem n useqdac",
+ "yourpassword": "Awal n uɛeddi:",
+ "userlogin-yourpassword": "Awal n uɛeddi",
+ "userlogin-yourpassword-ph": "Sekcem awal-ik(im) n uɛeddi",
+ "createacct-yourpassword-ph": "Sekcem awal n uɛeddi",
+ "yourpasswordagain": "Ɛiwed ssekcem awal n uɛeddi",
+ "createacct-yourpasswordagain": "Sentem awal n uɛeddi",
+ "createacct-yourpasswordagain-ph": "Sekcem awal n uɛeddi tikelt nniḍen",
+ "userlogin-remembermypassword": "Eǧǧ taɣimit inu turmidt",
+ "userlogin-signwithsecure": "Seqdec tuqqna yettwaḥerzen",
+ "cannotlogin-title": "Ur izmir ara ad yeqqen",
+ "cannotlogin-text": "Tuqqna d tawezɣit.",
+ "cannotloginnow-title": "Ur izmir ara ad yeqqen tura",
+ "cannotloginnow-text": "Tuqqna d tawezɣit ticki tseqdaceḍ $1.",
+ "cannotcreateaccount-title": "Ur izmir ara ad yernu imiḍanen",
+ "cannotcreateaccount-text": "Timerna srid n imiḍanen n iseqdacen ur termid ara ɣef uwiki-agi.",
+ "yourdomainname": "Taɣult inek",
+ "password-change-forbidden": "Ur zemreḍ ara ad beddeleḍ awalen n uɛaddi ɣef uwiki agi.",
+ "externaldberror": "Yella ugul aberrani n database neɣ ur tettalaseḍ ara ad tbeddleḍ isem an wemseqdac aberrani inek.",
+ "login": "Kcem",
+ "login-security": "Senqed timagit-ik",
+ "nav-login-createaccount": "Kcem / Xleq isem n wemseqdac",
+ "logout": "Ffeɣ",
+ "userlogout": "Ffeɣ",
+ "notloggedin": "Ur tekcimeḍ ara",
+ "userlogin-noaccount": "Ur tesɛiḍ ara amiḍan ?",
+ "userlogin-joinproject": "Ddukkel ar {{SITENAME}}",
+ "createaccount": "Xleq amivan",
+ "userlogin-resetpassword-link": "Ettuḍ awal n uɛaddi ?",
+ "userlogin-helplink2": "Tallelt i tuqqna",
+ "userlogin-loggedin": "Teqqneḍ yakan am {{GENDER:$1|$1}}. Seqdec tiferkit ddaw-agi iwakken ad teqqneḍ s umiḍan nniḍen.",
+ "userlogin-reauth": "Snulfud amiḍan nniḍen",
+ "userlogin-createanother": "Snulfud amiḍan nniḍen",
+ "createacct-emailrequired": "Tansa email",
+ "createacct-emailoptional": "Tansa email (axetṛan)",
+ "createacct-email-ph": "Sekcem tansa email inek(m)",
+ "createacct-another-email-ph": "Sekcem tansa email",
+ "createaccountmail": "Seqdec awal n uɛaddi agacuran akudan dɣa ceggeε-it ar tansa email yemlen",
+ "createacct-realname": "Isem n tidets (axetṛan)",
+ "createacct-reason": "Taɣẓint",
+ "createacct-reason-ph": "Ayɣer ad snulfuḍ amiḍan nniḍen",
+ "createacct-reason-help": "Izen yettwaseknen deg uɣmis n tmerna n umiḍan",
+ "createacct-submit": "Rnu amiḍan-ik(m)",
+ "createacct-another-submit": "Rnu amiḍan",
+ "createacct-continue-submit": "Kemmel timerna n umiḍan",
+ "createacct-another-continue-submit": "Kemmel timerna n umiḍan",
+ "createacct-benefit-heading": "{{SITENAME}} yetwexdem sɣur medden am kečč/kem.",
+ "createacct-benefit-body1": "{{PLURAL:$1|abeddel|ibeddilen}}",
+ "createacct-benefit-body2": "{{PLURAL:$1|asebter|isebtar}}",
+ "createacct-benefit-body3": "{{PLURAL:$1|atekki amaynut|ittekkiyen imaynuten}}",
+ "badretype": "Awal n tbaḍnit amezwaru d wis sin mačči d kif-kif.",
+ "userexists": "Isem n wemseqdac yeddem-as amdan wayeḍ. Fren yiwen nniḍen.",
+ "loginerror": "Agul n ukcam",
+ "createacct-error": "Tuccda deg usnulfu n umiḍan",
+ "createaccounterror": "Ulamek ad nesnulfu amiḍan: $1",
+ "nocookiesnew": "Isem n wemseqdac-agi yettwaxleq, meɛna ur tekcimeḍ ara. {{SITENAME}} yesseqdac ikukiyen (cookies) iwakken ad tkecmeḍ. Tekseḍ ikukiyen-nni. Eǧǧ-aten, umbeɛd kecm s yisem n wemseqdac akk d wawal n tbaḍnit inek.",
+ "nocookieslogin": "{{SITENAME}} yesseqdac ikukiyen (cookies) iwakken ad tkecmeḍ. Tekseḍ ikukiyen-nni. Eǧǧ-aten iwakken ad tkecmeḍ.",
+ "nocookiesfornew": "Amiḍan n useqdac ur d-isnulfu ara, acku ur nezmer ara an sulu azar-is.\nSelken ma sermedeḍ \"cookies\", sismeḍ asebter dɣa εreḍ tikkelt nniḍen.",
+ "noname": "Ur tefkiḍ ara isem n wemseqdac ṣaḥiḥ.",
+ "loginsuccesstitle": "Taqqneḍ",
+ "loginsuccess": "<strong>Tkecmeḍ ar {{SITENAME}} s yisem n wemseqdac \"$1\".</strong>",
+ "nosuchuser": "Aseqdac $1 ulac-it d-agi.\nIsmawen n iseqdacen ṭṭafaṛen taruẓi n usekkil.\nSenqed tira, neɣ [[Special:CreateAccount|rnu amiḍan amaynut]].",
+ "nosuchusershort": "Ulac isem n wemseqdac s yisem \"$1\". Ssenqed tira n yisem-nni.",
+ "nouserspecified": "Yessefk ad tefkeḍ isem n wemseqdac.",
+ "login-userblocked": "Aseqdac agi i sewḥel. Tuqqna t-ugwi.",
+ "wrongpassword": "Awal n tbaḍnit ɣaleṭ. Ɛreḍ daɣen",
+ "wrongpasswordempty": "Awal n tbaḍnit ɣaleṭ. Ɛreḍ daɣen",
+ "passwordtooshort": "Awal-ik (im) n uɛaddi ilaq ad i sɛu adday {{PLURAL:$1|1 asekkil|$1 isekkilen}}.",
+ "password-name-match": "Ilaq awal n uɛaddi ad yili imeẓli s-isem n useqdac.",
+ "password-login-forbidden": "aseqdac agi d awal n uɛaddi agi d-izenbigen.",
+ "mailmypassword": "Awennez tikkelt nniḍen n awal uɛaddi",
+ "passwordremindertitle": "Asmekti n wawal n tbaḍnit seg {{SITENAME}}",
+ "passwordremindertext": "Amdan (waqila d kečč/kem, seg tansa IP $1) yesteqsa iwakken a nazen\nAwal n uɛaddi amaynut i {{SITENAME}} ($4). Awal n uɛaddi i wemseqdac \"$2\" yuɣal-d tura \"$3\".\nMliḥ lukan tkecmeḍ u tbeddleḍ Awal n uɛaddi tura.\nTasewti n awal agi n uɛaddi amaynut ad yaweḍ deg {{PLURAL:$5|yiwen ass|$5 ussan}}\n\nLukan mačči d kečč i yesteqsan naɣ tecfiḍ ɣef awal n uɛaddi, tzemreḍ ad tkemmleḍ mebla ma tbeddleḍ awal n uɛaddi.",
+ "noemail": "\"$1\" ur yesɛi ara email.",
+ "noemailcreate": "Ilaq ad efkeḍ tansa e-mail i sɛan aseɣbel.",
+ "passwordsent": "Awal n tbaḍnit amaynut yettwazen i emal inek, aylaw n \"$1\".\nG leɛnaya-k, kcem tikelt nniḍen yis-s.",
+ "blocked-mailpassword": "Tansa-ik IP tewḥel i unifel. Akken ad nsewḥel yir aseqdec, ur tezmireḍ ara ad tesqedceḍ tiririt n wawal uffir si tansa-agi IP.",
+ "eauthentsent": "Yiwen email yetweceggeε ar tansa id efkeḍ.\nUqbel ad n-ceggeε email nniḍen, ilaq ad ḍfereḍ ayen yellan deg email dɣa ad sergegeḍ amiḍan agi d win inek(m).",
+ "throttled-mailpassword": "Neceggɛed yakan tirawt n uwennez i awal-ik/im n uɛaddi deg {{PLURAL:$1|asrag agi aneggaru|$1 isragen agi ineggura}}. Awennez n uwal n uɛaddi yettwaceggaɛ tikelt kan deg {{PLURAL:$1|asrag|$1 isragen}}.",
+ "mailerror": "Agul asmi yettwazen e-mail: $1",
+ "acct_creation_throttle_hit": "Inebgawen iseqdacen tansa IP-ik rnan {{PLURAL:$1|n umiḍan|$1 n imiḍanen}} deg $2 n yisragen ineggura, d ayen yessawḍen ar talast tafellayt yettwasirgen deg uzilal-agi n wakud.\nIhi, timerna n imiḍanen i yinebgawen iseqdacen tansa-agi IP tewḥel akka tura.",
+ "emailauthenticated": "Tansa-ik(im) imayl tettwasentem di $2 af $3.",
+ "emailnotauthenticated": "Tansa email inek mazal ur tettuɛqel. Ur d netceggaɛ ara email i yal tiseɣnin agi.",
+ "noemailprefs": "Efk tansa e-mail iwakken ad leḥḥun iḍaɣaren-nni.",
+ "emailconfirmlink": "Sentem tansa-ik imayl",
+ "invalidemailaddress": "Tansa e-mail-agi ur telhi, ur tesɛi ara taseddast n lɛali. Ssekcem tansa e-mail s taseddast n lɛali neɣ ur tefkiḍ acemma.",
+ "cannotchangeemail": "Ur t-zemreḍ ara ad beddeleḍ tansa e-mail deg uwiki agi.",
+ "emaildisabled": "Asmel agi ur yezmer ara ad i cegaɛ e-mail.",
+ "accountcreated": "Isem n wemseqdac yettwaxleq",
+ "accountcreatedtext": "Amiḍan n useqdac i [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|asqerdec]]) yettwarna.",
+ "createaccount-title": "Asnulfu n umiḍan i {{SITENAME}}",
+ "createaccount-text": "Albeɛḍ yesnulfu-d amiḍan i tansa e-amil inek/inem ɣef {{SITENAME}} ($4) s-isem n-useqdac « $2 », s awal n uɛaddi « $3 ».\nIlaq tura ad lldiḍ taɣimit dɣa ad beddeleḍ awal ik/im n uɛaddi.",
+ "login-throttled": "Tɛerdeḍ ad qqeneḍ aṭas tiqwal deg dqiqat agi iɛddan.\nIlaq ad rǧuḍ $1 uqbel ad ɛerdeḍ tikkelt nniḍen.",
+ "login-abort-generic": "Awraḍ-ik n tuqqna ur yeddi ara",
+ "login-migrated-generic": "Amiḍan-ik iguǧ, isem-ik n useqdac qerǧin yella deg uwiki-agi.",
+ "loginlanguagelabel": "Tutlayt: $1",
+ "suspicious-userlogout": "Asuter n usenser yugwi acku yella ugur s iminig naɣ s tazarkatut n uqeddac proxy.",
+ "createacct-another-realname-tip": "Isem n ṣṣeḥ d-axeṭran.\nMa teɛzemeḍ a t-tefkeḍ, ad yettuseqdac iwakken ad snen medden anwa yuran tikkin inek.",
+ "pt-login": "Qqen",
+ "pt-login-button": "Qqen",
+ "pt-login-continue-button": "Kemmel tuqqna",
+ "pt-createaccount": "Rnu amiḍan",
+ "pt-userlogout": "Ffeɣ",
+ "php-mail-error-unknown": "anezri warisem deg tawuri mail() n PHP",
+ "user-mail-no-addy": "Ɛred ad icegaɛ e-mail war tansa e-mail",
+ "user-mail-no-body": "Arram n uceggaɛ email s tafekka tilemt neɣ d-awezlan aṭas.",
+ "changepassword": "Beddel awal n tbaḍnit",
+ "resetpass_announce": "Akken ad tfakeḍ ajerred-ik, yessefk ad tmuddeḍ awal uffir amaynut.",
+ "resetpass_header": "Beddel awal n uɛassi n umiḍan",
+ "oldpassword": "Awal n tbaḍnit aqdim:",
+ "newpassword": "Awal n tbaḍnit amaynut:",
+ "retypenew": "Ɛiwed ssekcem n tbaḍnit amaynut:",
+ "resetpass_submit": "Eg awal n tbaḍnit u kcem",
+ "changepassword-success": "Awal-ik uffir ibeddel!",
+ "changepassword-throttled": "Tɛerdeḍ ad qqeneḍ aṭas tiqwal deg dqiqat agi iɛddan.\nIlaq ad rǧuḍ $1 uqbel ad ɛerdeḍ tikkelt nniḍen.",
+ "botpasswords": "Iwalen uffiren n iṛubuten",
+ "botpasswords-disabled": "Awalen uffiren n iṛubuten nsan.",
+ "botpasswords-no-central-id": "Akken ad tesqedceḍ awalen uffiren n iṛubuten, yessefk ad teqqneḍ amiḍan yettwaslemsen.",
+ "botpasswords-existing": "Awalen uffiren n uṛubuten yellan",
+ "botpasswords-createnew": "Rnu awal uffir n iṛubuten amaynut",
+ "botpasswords-editexisting": "Ẓreg awal uffir n iṛubuten yellan",
+ "botpasswords-label-appid": "Isem n uṛubut:",
+ "botpasswords-label-create": "Rnu",
+ "botpasswords-label-update": "Leqqem",
+ "botpasswords-label-cancel": "Sefsex",
+ "botpasswords-label-delete": "Kkes",
+ "botpasswords-label-resetpassword": "Wennez awal uffir",
+ "botpasswords-label-grants": "Izerfan yettwasnasen:",
+ "botpasswords-label-grants-column": "Ttunefken izerfan",
+ "botpasswords-bad-appid": "Isem n uṛubut \"$1\" mačči d ameɣtu.",
+ "botpasswords-insert-failed": "Ur isaweḍ ara ad yernu isem n uṛubut \"$1\". Yettwarna yakan?",
+ "botpasswords-update-failed": "Maqqdesh leqqem isen n uṛubut ''$1''. Rah Kkes ?",
+ "botpasswords-created-title": "Awal uffir n iṛubuten yettwarna",
+ "botpasswords-created-body": "Awal n uâddi n iṛubuten l isem n uṛubut ''$1'' n {{GENDER:$2|useqdac}} ''$2'' rnu",
+ "botpasswords-updated-title": "Awal n uâddi n iṛbuten ibeddel",
+ "botpasswords-updated-body": "Awal n uâddi n iṛubuten l isem n uṛubut ''$1'' n {{GENDER:$2|useqdac}} ''$2'' ibeddel",
+ "botpasswords-deleted-title": "Awal uffir n iṛubuten yettwakkes",
+ "botpasswords-deleted-body": "Awal n uâddi n uṛubut \"$1\" n {{GENDER:$2|useqdac}} \"$2\" yettwakkes.",
+ "botpasswords-no-provider": "Asaǧǧaw n tɣimit n wawal n uâddi n iṛubuten ulac-it.",
+ "resetpass_forbidden": "Ur zemreḍ ara ad beddeleḍ awalen n uɛaddi",
+ "resetpass_forbidden-reason": "Ur tezmireḍ ara ad tẓergeḍ awal uffir : $1",
+ "resetpass-no-info": "Ilaq ad qqeneḍ iwakken ad ẓṛeḍ asebter agi.",
+ "resetpass-submit-loggedin": "Beddel awal n uɛaddi",
+ "resetpass-submit-cancel": "Semmewet",
+ "resetpass-wrong-oldpass": "Awal n uɛaddi d askudan neɣ amira mačči d ameɣtu.\nAhat tbeddleḍ yakanawal-ik uffir neɣ tsutreḍ-d askudan-nniḍen.",
+ "resetpass-temp-password": "Awal n uɛaddi amakud",
+ "resetpass-abort-generic": "Asiɣzef yesemmewet abeddel n uwal n uɛaddi.",
+ "passwordreset": "Awennez tikkelt nniḍen n awal uɛaddi",
+ "passwordreset-text-one": "Ččur tiferkit agi iwakken ad wennezeḍ awal-ik/im n uɛaddi.",
+ "passwordreset-text-many": "{{PLURAL:$1|Čcur yiwet n tiɣwezza iwakken ad rmeseḍ awal n uɛaddi uɛḍil deg tirawt.}}",
+ "passwordreset-disabled": "Awennez n awal uɛaddi yensa deg uwiki agi.",
+ "passwordreset-emaildisabled": "Tiseɣnin email nsant ɣef wiki agi.",
+ "passwordreset-username": "Isem n useqdac:",
+ "passwordreset-domain": "Talɣut :",
+ "passwordreset-email": "Tansa e-mail:",
+ "passwordreset-emailtitle": "Tilɣa n umiḍan ɣef {{SITENAME}}",
+ "passwordreset-emailtext-ip": "Yiwen (Ahat kečč/kem, seg tansa IP $1) yessutered awennez n awal n uɛaddi i {{SITENAME}} ($4). {{PLURAL:$3|Amiḍan n useqdac agi yeqqen|imiḍanen n iseqdacen agi qqenen}} s tansa e-mail agi :\n\n$2\n\n{{PLURAL:$3|Awal n uɛaddi uɛḍil agi ad i aff tasewti-s|Awalen n uɛaddi uɛḍilen agi ad affen taseweti nsen}} deg {{PLURAL:$5|yiwen ass|$5 ussan}}. Ilaq tura ad qqeneḍ dɣa ad freneḍ awal n uɛaddi amaynut. Lukan mačči d kečč/kem i xedmen asuter agi, naɣ tecfiḍ tura i awal n uɛaddi inek/inem, tzemreḍ ad eǧǧeḍ izen agi.",
+ "passwordreset-emailtext-user": "Aseqdac $1 ɣef {{SITENAME}} yessutered awennez n awal n uɛaddi i {{SITENAME}} ($4). {{PLURAL:$3|Amiḍan n useqdac agi yeqqen|imiḍanen n iseqdacen agi qqenen}} s tansa e-mail agi :\n\n$2\n\n{{PLURAL:$3|Awal n uɛaddi uɛḍil agi ad i aff tasewti-s|Awalen n uɛaddi uɛḍilen agi ad affen taseweti nsen}} deg {{PLURAL:$5|yiwen ass|$5 ussan}}. Ilaq tura ad qqeneḍ dɣa ad freneḍ awal n uɛaddi amaynut. Lukan mačči d kečč/kem i xedmen asuter agi, naɣ tecfiḍ tura i awal n uɛaddi inek/inem, tzemreḍ ad eǧǧeḍ izen agi.",
+ "passwordreset-emailelement": "Isem n useqdac : \n$1\n\nAwal n uɛddi akudan : \n$2",
+ "passwordreset-emailsentemail": "Ma yella imayl-agi icudd ar umiḍan-ik, awennez n wawal uffir ad yettwazen ar yimayl.",
+ "passwordreset-invalidemail": "Tansa imayl d tarameɣtut",
+ "changeemail": "Beddel neɣ kkes tansa n imayl",
+ "changeemail-no-info": "Ilaq ad qqeneḍ iwakken ad ẓṛeḍ asebter agi.",
+ "changeemail-oldemail": "Tansa e-mail n tura:",
+ "changeemail-newemail": "Tansa e-mail tamaynut:",
+ "changeemail-newemail-help": "Laissez ce champ vide si vous voulez supprimer votre adresse de courriel. Sans adresse de courriel renseignée, vous ne pourrez plus réinitialiser votre mot de passe en cas d’oubli ni recevoir de courriels à partir de ce wiki.",
+ "changeemail-none": "(ulac)",
+ "changeemail-password": "Awal-ik/im n uɛaddi ɣef {{SITENAME}}:",
+ "changeemail-submit": "Beddel tansa e-mail",
+ "changeemail-throttled": "Tɛerdeḍ ad qqeneḍ aṭas tiqwal.\nIlaq ad rǧuḍ $1 uqbel ad ɛerdeḍ tikkelt nniḍen.",
+ "changeemail-nochange": "Ttxilek sekcem tansa i imayl nniḍen.",
+ "resettokens": "Wennez tiddas",
+ "resettokens-text": "D-agi tzemreḍ ad twennezeḍ tiddas i ɛemmeden ad kecmeḍ ar isefka usligen i qqenen ar amiḍan inek/inem.\n\nIlaq ad twennezeḍ tiddas ma tferqeḍ-ten s tuccḍa s umseqdac nniḍen neɣ ma amiḍan inek/inem yexṣer.",
+ "resettokens-no-tokens": "Ulac tiddas an wennez.",
+ "resettokens-tokens": "Tiddas:",
+ "resettokens-token-label": "$1 (azal amiran: $2)",
+ "resettokens-watchlist-token": "Tiddest i usuddem (Atom/RSS) web n [[Special:Watchlist|ibeddilen n isebtar n umuɣ inek/inem n uḍfar]]",
+ "resettokens-done": "Tiddas i wennezen.",
+ "resettokens-resetbutton": "Wennez tiddas i fernen",
+ "bold_sample": "Aḍris aberbuz",
+ "bold_tip": "Aḍris aberbuz",
+ "italic_sample": "Aḍris aṭalyani",
+ "italic_tip": "Aḍris aṭalyani",
+ "link_sample": "Azwel n uzday",
+ "link_tip": "Azday zdaxel",
+ "extlink_sample": "http://www.example.com azwel n uzday",
+ "extlink_tip": "Azday aberrani (cfu belli yessefk at tebduḍ s http://)",
+ "headline_sample": "Aḍris n uzwel azellum",
+ "headline_tip": "Aswir 2 n uzwel azellum",
+ "nowiki_sample": "Sideff da tirra bla taseddast(formatting) n wiki",
+ "nowiki_tip": "Ttu taseddast n wiki",
+ "image_tip": "Tugna yettussekcmen",
+ "media_tip": "Azday n ufaylu media",
+ "sig_tip": "Azmul inek s uzemz",
+ "hr_tip": "Ajerriḍ aglawan (ur teččerɛiḍ ara)",
+ "summary": "Agzul:",
+ "subject": "Asentel:",
+ "minoredit": "Wagi d abeddel afessas",
+ "watchthis": "Ɛass asebter-agi",
+ "savearticle": "Beddel asebter",
+ "savechanges": "Sekles asnifel",
+ "publishpage": "Suffeɣ-d asebter",
+ "publishchanges": "Suffeɣ-d asnifel",
+ "preview": "azar-asekdan",
+ "showpreview": "Ssken azar-asekdan",
+ "showdiff": "Ssken ibeddlen",
+ "blankarticle": "<strong>Ɣur-ek:</strong> Asebter d-tesɣenweḍ d ilem.\nMayel tkketaḍ daɣen ɣef \"$1\", ad iɣnew usebter war agbur.",
+ "anoneditwarning": "<strong>Ɣur-k:</strong> ur teqqineḍ ara. Tansa-ik IP ad d-ban i yal yiwen ma yella ur teggiḍ ara abeddel. Ma yella <strong>[$1 teqqneḍ]</strong> neɣ <strong>[$2 rnu amiḍan]</strong>, abeddel-ik ad ittusemmi s yisem-ik, s ufareṣ n tignatin-nniḍen.",
+ "anonpreviewwarning": "<em>Ur tesuluḍ ara. Aḥraz ad yekles tansa IP inek/inem deg umezruy n ibeddilen n usebter.</em>",
+ "missingsummary": "<strong>Ur tettuḍ ara:</strong> Ur tefkiḍ ara azwel i ubeddel inek. Lukan twekkiḍ ''Smekti'' ''$1'' tikelt nniḍen, abeddel inek ad yettusmekti mebla azwel.",
+ "missingcommenttext": "Ssekcem awennit deg ukessar.",
+ "missingcommentheader": "<strong>Asmekti:</strong> ur d-muddeḍ ara asentel n uwennit-agi.\nMa tsenndeḍ tikelt-nniḍen ɣef \"$1\", abeddel-ik ad yettwasekles s war asentel.",
+ "summary-preview": "Taskant n ugzul n ubeddel:",
+ "subject-preview": "Taskant n usentel:",
+ "blockedtitle": "Amseqdac iɛekkel",
+ "blockedtext": "<strong>Amiḍan-ik n useqdac neɣ tansa n IP weḥlen.</strong>\n\nAsewḥel yega-t $1.\nTaɣẓint d tagi : <em>$2</em>.\n\n* Tazwara n usewḥel : $8\n* Tagara n usewḥel : $6\n* Amiḍan iweḥlen : $7.\n\n\nTzemreḍ ad tnermseḍ $1 neɣ [[{{MediaWiki:Grouppage-sysop}}|anedbal]]-nniḍen akken ad tsmelayem.\nUr tezmireḍ ara ad tesqedceḍ tawuri \"nemres aseqdac-agi\" ma yella tella tensa tameɣtut deg[[Special:Preferences|ismenyifen n useqdac]], udiɣ ma yella tawuri-agi ur tewḥil ara. Tansa-ik IP n tura d $3, ID n usewḥeld #$5.\nSuddu-d akk talɣut-agi deg tuttriwin ara d-azdneḍ.",
+ "autoblockedtext": "Tansa-ik IP tewḥel s wudem awurman acku i tt-yesseqdacen yesweḥli-t $1.\n\n\nTaɣẓint d tagi :\n:<em>$2</em>\n\n* Tazwara n usewḥel : $8\n* Tagara n usewḥel : $6\n* Amiḍan iweḥlen : $7.\n\n\nTzemreḍ ad tnermseḍ $1 neɣ [[{{MediaWiki:Grouppage-sysop}}|anedbal]]-nniḍen akken ad tsmelayem.\nUr tezmireḍ ara ad tesqedceḍ tawuri \"nermres aseqdac-agi\" ma yella tella tensa tameɣtut deg[[Special:Preferences|ismenyifen n useqdac]], udiɣ ma yella tawuri-agi ur tewḥil ara. \n\nTansa-ik IP n tura d $3, ID n usewḥeld #$5.\nSuddu-d akk talɣut-agi deg tuttriwin ara d-azdneḍ.",
+ "blockednoreason": "Ulac taɣẓint",
+ "whitelistedittext": "Yessefk ad $1 iwakken ad tbeddleḍ isebtar.",
+ "confirmedittext": "Yessefk ad tsentmeḍ tansa e-mail inek uqbel abeddel. Xtar tansa e-mail di [[Special:Preferences|isemyifiyen n wemseqdac]].",
+ "nosuchsectiontitle": "Ulamek an af tigezmi",
+ "nosuchsectiontext": "Tɛerḍeḍ ad tbeddleḍ tigezmi ur llan ara.",
+ "loginreqtitle": "Yessefk ad tkecmeḍ",
+ "loginreqlink": "Kcem",
+ "loginreqpagetext": "Yessefk $1 iwakken ad teẓriḍ isebtar wiyaḍ.",
+ "accmailtitle": "Awal n uɛaddi yettwazen.",
+ "accmailtext": "Awal n uɛaddi id yuran s ugacur i [[User talk:$1|$1]] yetweceggaɛ i $2.\nYezmer ad yetbeddel ɣef usebtar [[Special:ChangePassword|Abeddel n awal uɛddi]] sakin tuqqna.",
+ "newarticle": "(Amaynut)",
+ "newarticletext": "Tḍefreḍ azday ɣer usebter mazal ur yettwaxleq ara.\nAkken ad txelqeḍ asebter-nni, aru deg tenkult i tella deg ukessar\n(ẓer [$1 asebter n tallalt] akken ad tessneḍ kter).\nMa tɣelṭeḍ, wekki kan ɣef tqeffalt \"Back/Précédent\" n browser/explorateur inek.",
+ "anontalkpagetext": "----\n<em>Aqla-k deg usebter n usqerdec n useqdac udrig ur yernan ara yakan amiḍan neɣ ur t-yesseqdacen ara </em>.\nƔef aya, yessefk ad nseqdec tansa-is IP akken ad t-nissin.\nTansa IP tezmer ad tettwabḍu sɣuṛ ddeqs n iseqdacen.\nMa telliḍ d {{GENDER:|||}} d {{GENDER:|aseqdac udrig|taseqdact tudrigt}} udiɣ twalaḍ d akken iwenniten ur k-neɛni ara ttwaznen-ak-d, tzemreḍ [[Special:CreateAccount|ad ternuḍ amiḍan]] neɣ [[Special:UserLogin|ad teqqneḍ]] akken ad tzegleḍ akk ar zdat anexluḍ akked imttekkiyen udrigen.",
+ "noarticletext": "Ulac aḍris deg usebter-agi akka tura Tzemreḍ [[Special:Search/{{PAGENAME}}|ad tnadiḍ aswel n usebter-agi]] deg isebtar-nniḍen,<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} nadi ti temhalin icudden ɣur-s],\nneɣ [{{fullurl:{{FULLPAGENAME}}|action=edit}} rnu asebter-agi]</span",
+ "noarticletext-nopermission": "Imira ulac aḍris deg usebter agi.\nTzemreḍ [[Special:Search/{{PAGENAME}}|ad nadiḍ ɣef azwel agi]] deg isebtaren nniḍen,\nnaɣ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|asebter={{FULLPAGENAMEE}}}} ad nadiḍ deg iɣmisen iqqenen]</span>.",
+ "missing-revision": "Tacaggart #$1 n usebter s isem « {{FULLPAGENAME}} » ulac-itt.\n\nAcku azday n umezruy, ɣef wayen tsennedeḍ, d-aqbur. Asebter yemḥa.\nTzemreḍ ad affeḍ tilɣa deg [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} uɣmis n isebtar yemḥan].",
+ "userpage-userdoesnotexist": "Amiḍan n useqdac « <nowiki>$1</nowiki> » ur yekles ara. Ilaq ad selkeneḍ ma tebɣiḍ ad snulfuḍ asebter agi.",
+ "userpage-userdoesnotexist-view": "Amiḍan n useqdac ''$1'' ur yekles ara.",
+ "blocked-notice-logextract": "Aseqdac agi yekyef.\nAsekcem aneggaru n useklas n ikyafen yella ddaw agi:",
+ "clearyourcache": "<strong>Tamawt :</strong> deffir mi nsekles ibeddilen-ik, yessefk ad tḥettmeḍ asmiren ummid n tuffirt n yiminig-ikakken ad twaliḍ ibeddilen.\n* <strong>Firefox / Safari :</strong> eǧǧ afus-ik ɣef taqeffalt <em>Maj</em> (<em>Shift</em>) sakin senned ɣef tqeffalt <em>Smiren</em> neɣ senned <em>Ctrl-F5</em> neɣ <em>Ctrl-R</em> (<em>⌘-R</em> di Mac) \n* <strong>Google Chrome :</strong> senned ɣef <em>Ctrl-Maj-R</em> (<em>⌘-Shift-R</em> di Mac) \n* <strong>Internet Explorer :</strong> senned ɣef tqeffalt <em>Ctrl</em> udiɣ ɣef tqeffalt <em>Smiren</em> neɣ senned ɣef <em>Ctrl-F5</em> \n* <strong>Opera :</strong> ddu ar wumuɣ <em>Umuɣ → Iɣewwaṛen</em> (<em>Opera → Ismenyifen</em> ɣef Mac) sakin ɣef <em>Tabaḍnit & taɣellit → Sfeḍ isefka n usnirem → Tugniwin akked d iful=yla n tuffirt</em>.",
+ "usercssyoucanpreview": "<strong>taxbalut:</strong> Sseqdec taqeffalt « {{int:showpreview}} » iwakken ad tɛerḍeḍ asebter CSS inek/inem amaynut uqbel ad aklasteḍ.",
+ "userjsonyoucanpreview": "<strong>taxbalut:</strong> Sseqdec taqeffalt « {{int:showpreview}} » iwakken ad tɛerḍeḍ asebter JSON inek/inem amaynut uqbel ad aklasteḍ.",
+ "userjsyoucanpreview": "<strong>taxbalut:</strong> Sseqdec taqeffalt « {{int:showpreview}} » iwakken ad tɛerḍeḍ asebter JavaScript inek/inem amaynut uqbel ad aklasteḍ.",
+ "usercsspreview": "<strong>Cfu-d, wagi d-azaraskan n usebter ik/im n CSS.\nMmazal ur yettusmekti ara!</strong>",
+ "userjsonpreview": "<strong>Cfu-d, wagi d-azaraskan n usebter ik/im n JSON.\nMmazal ur yettusmekti ara!</strong>",
+ "userjspreview": "<strong>Cfu-d, wagi d-azaraskan n usebter ik/im n JavaScript.\nMmazal ur yettusmekti ara!</strong>",
+ "sitecsspreview": "<strong>Smekti belli aql-ak tɛerḍeḍ asebter CSS agi inek kan.\nMazal ur yettusmekti ara!</strong>",
+ "sitejsonpreview": "<strong>Smekti belli aql-ak tɛerḍeḍ asebter JSON config agi inek kan.\nMazal ur yettusmekti ara!</strong>",
+ "sitejspreview": "<strong>Smekti belli aql-ak tɛerḍeḍ asebter JavaScript inek kan.\nMazal ur yettusmekti ara!</strong>",
+ "editing": "Aglaf n $1",
+ "editingsection": "Aglaf n $1 (tagzemt)",
+ "search-result-size": "$1 ({{PLURAL:$2|1 awal|$2 awalen}})",
+ "search-section": "(tagzemt $1)",
+ "searchresultshead": "Iruzzi",
+ "prefs-searchoptions": "Iruzzi",
+ "nbytes": "$1 {{PLURAL:$1|byte|bytes}}",
+ "linksearch-ok": "Iruzzi",
+ "undelete-search-submit": "Iruzzi",
+ "sp-contributions-submit": "Iruzzi",
+ "ipblocklist-submit": "Iruzzi",
+ "tooltip-search": "Iruzzi {{SITENAME}}",
+ "show-big-image-size": "$1 × $2 pixels",
+ "ilsubmit": "Iruzzi",
+ "days": "{{PLURAL:$1|$1 ass|$1 ussan}}",
+ "fileduplicatesearch-submit": "Iruzzi",
+ "searchsuggest-search": "Iruzzi",
+ "duration-days": "$1 {{PLURAL:$1|ass|ussan}}"
+}
"recentchangeslinked-feed": "Sorodne spremembe",
"recentchangeslinked-toolbox": "Sorodne spremembe",
"recentchangeslinked-title": "Spremembe, povezane z \"$1\"",
- "recentchangeslinked-summary": "Vnesite ime strani, da vidite spremembe strani, povezanih na ali s te strani. (Da vidite člane kategorije, vnesite Kategorija:Ime kategorije.)\nStrani z [[Special:Watchlist|vašega spiska nadzorov]] so <strong>odebeljene</strong>.",
+ "recentchangeslinked-summary": "Vnesite ime strani, da vidite spremembe strani, povezanih na ali s te strani. (Da vidite člane kategorije, vnesite {{ns:category}}:Ime kategorije.)\nStrani z [[Special:Watchlist|vašega spiska nadzorov]] so <strong>odebeljene</strong>.",
"recentchangeslinked-page": "Naslov strani:",
"recentchangeslinked-to": "Prikaži spremembe na določeno stran povezanih strani",
"recentchanges-page-added-to-category": "[[:$1]] dodano v kategorijo",
"rcfilters-filter-watchlistactivity-unseen-description": "Измене страница које нисте посетили од када су направљене измене.",
"rcfilters-filter-watchlistactivity-seen-label": "Погледане измене",
"rcfilters-filter-watchlistactivity-seen-description": "Измене страница које сте посетили од када су направљене измене.",
- "rcfilters-filtergroup-changetype": "Ð\92Ñ\80Ñ\81Ñ\82а измене",
+ "rcfilters-filtergroup-changetype": "Тип измене",
"rcfilters-filter-pageedits-label": "Измене страница",
"rcfilters-filter-pageedits-description": "Измене вики садржаја, расправа, описа категорија…",
- "rcfilters-filter-newpages-label": "СÑ\82ваÑ\80ање страница",
+ "rcfilters-filter-newpages-label": "Ð\9fÑ\80авÑ\99ење страница",
"rcfilters-filter-newpages-description": "Измене којима се стварају нове странице.",
"rcfilters-filter-categorization-label": "Измене категорија",
"rcfilters-filter-categorization-description": "Записи о страницама додатим или уклоњеним из категорија.",
"laggedslavemode": "Dej pozůr: Ta zajta może ńy mjeć nojnowszych aktualizacyjůw.",
"readonly": "Baza danych je zawarto",
"enterlockreason": "Naszkryflej sam powůd zawarćo bazy danych a za wjela (myńi-wjyncyj) ja uodymkńesz",
- "readonlytext": "Baza danych jest terozki zawarto\n- ńy do śe wćepywać nowych artikli ńi sprowjać już wćepanych. Powodym\nsům prawdopodańy czynnośći admińistracyjne. Po jejich zakůńczyńu cołko funkcjonalność bazy bydźe prziwrůcono.\nAdministrator, kery zablokowoł baza, podoł takie wyjaśńyńy:<br /> $1",
+ "readonlytext": "Baza danych je terŏzki zawartŏ na nowe informacyje i pōmiynianie przōdzij wkludzōnych. Je to nojpewnij skuli czynności administracyjnych. Po jejich skōńczyniu baza bydzie nazŏd fungować.\nAdministratōr, kery zablokowoł bazã, doł takie tuplikowaniy:<br /> $1",
"missing-article": "W databaźe ńy idzie nolyźć treść zajty „$1” $2.\n\nUobwykle je to spůsobiůne tym, że sznupoł żeś po ńyaktualnym linku na zmjyny mjyndzy půmjyńańami, abo do wyćepanyj wersyje z gyszichty sprowjyń zajty.\n\nEli tak ńy je, możno śe trefił feler we softwaru MediaWiki. Kej ja, pedz uo tym [[Special:ListUsers/sysop|admińistratorowi]] a podej mu adres URL.",
"missingarticle-rev": "(wersyjo#: $1)",
"missingarticle-diff": "(dyferencyjo: $1, $2)",
"viewyourtext": "We tekst zdrzůduowy tyj zajty możno dali filować, idźe go tyż kopjować.",
"protectedinterface": "Na tyj zajće znojduje śe tekst interfejsu uoprogramowańo, bestůż uůna je zawarto uod sprowjańo. Coby doćepnůńć abo sprowjić tůmaczyńa wszyskich serwerůw, użyj [https://translatewiki.net/ translatewiki.net], průjyktu lokalizacyji MediaWiki.",
"editinginterface": "''''Dej pozůr:''' Sprowjosz zajta, na keryj je tekst interfejsu uoprogramowańo. Pomjyńyńa na tyj zajće zmjyńům wyglůnd interfejsu lo inkszych użytkowńikůw. Coby doćepnůńć abo sprowjić tůmaczyńa, użyj [https://translatewiki.net/wiki/Main_Page?setlang=szl translatewiki.net].",
- "cascadeprotected": "Ta zajta je zawarto uod sprowjańo, po takymu, co uůna je załůnczůno na {{PLURAL:$1|nastympujůncyj zajće, kero zostoła zawarto|nastympujůncych zajtach, kere zostoły zawarte}} ze załůnczůnům uopcyjům dźedźiczyńo:\n$2",
+ "cascadeprotected": "Ta zajta je chrōniōnŏ ôd edycyje, skuli tego co je ôna wkludzōnŏ do {{PLURAL:$1|nastympujōncyj zajty, kerŏ ôstała ôchrōniōnŏ|nastympujōncych zajtach, kere ôstały ôchrōniōne}} ze załōnczōnōm ôpcyjōm erbowaniŏ:\n$2",
"namespaceprotected": "Ńy mosz uprowńyń, coby sprowjać zajty we raumje mjan '''$1'''.",
"customcssprotected": "Ńy mosz uprawńyń do sprowjańo tyj zajty, bo na ńij sům uosobiste sztalowańo inkszego użytkowńika.",
"customjsprotected": "Ńy mosz uprawńyń do sprowjańo tyj zajty, bo na ńij sům uosobiste sztalowańo inkszego użytkowńika.",
"noname": "To ńy je poprowne mjano użytkowńika.",
"loginsuccesstitle": "Logowańy udane",
"loginsuccess": "'''Terozki jeżeś zalogowany do {{SITENAME}} kej \"$1\".'''",
- "nosuchuser": "Ńy ma sam użytkowńika uo mjańe \"$1\".\nSprowdź szrajbůng, abo [[Special:CreateAccount|utwůrz nowe kůnto]].",
+ "nosuchuser": "Niy ma używŏcza ô mianie \"$1\".\nBadnij szrajbōng, abo [[Special:CreateAccount|sprŏw nowe kōnto]].",
"nosuchusershort": "Ńy mo sam użytkowńika uo mjańe \"$1\".",
"nouserspecified": "Podej mjano użytkowńika.",
"login-userblocked": "Tyn sprowjorz mo zawarte sprowjyńa. Ńy idźe śe zalogować.",
"savechanges": "மாற்றங்களைச் சேமி",
"publishpage": "பக்கத்தைப் பதிப்பிடுக",
"publishchanges": "மாற்றங்களைப் பதிப்பிடுக",
+ "publishchanges-start": "மாற்றங்களைப் பதிப்பிடுக…",
"preview": "முன்தோற்றம்",
"showpreview": "முன்தோற்றம் காட்டு",
"showdiff": "மாற்றங்களைக் காட்டு",
"AryanSogd",
"ToJack",
"Vashgird",
- "Fitoschido"
+ "Fitoschido",
+ "TajikMaterialist"
]
},
"tog-underline": "Пайвандҳо хаткашида:",
"fri": "Ҷу",
"sat": "Шн",
"january": "январ",
- "february": "феврал",
+ "february": "Феврал",
"march": "март",
"april": "апрел",
"may_long": "май",
"action-edit": "бу битне үзгәртү",
"action-createpage": "бу битне төзү",
"action-createtalk": "бу бәхәс битен төзү",
+ "action-createaccount": "бу кулланучы язмасын ясау",
"action-move": "бу битне күчерергә",
"action-sendemail": "электрон хат җибәрү",
"nchanges": "$1 {{PLURAL:$1|үзгәртү}}",
"newsectionsummary": "/* $1 */ яңа бүлек",
"rc-enhanced-expand": "Ваклыкларны күрсәтү",
"rc-enhanced-hide": "Ваклыкларны яшерү",
+ "rc-old-title": "башта «$1» буларак ясала",
"recentchangeslinked": "Бәйләнешле үзгәртүләр",
"recentchangeslinked-feed": "Бәйләнешле үзгәртүләр",
"recentchangeslinked-toolbox": "Бәйләнешле үзгәртүләр",
"unwatch": "Күзәтмәү",
"unwatchthispage": "Күзәтүне туктат",
"notanarticle": "Мәкалә түгел",
- "watchlist-details": "Күзәтү исемлегегездә, бәхәс битләрен санамыйча, {{PLURAL:$1|$1 бит}} бар.",
+ "watchlist-details": "Күзәтү исемлегегездә (бәхәс битләре белән бергә) {{PLURAL:$1|$1 бит}}.",
"wlheader-enotif": "Электрон почта аша белдерүләр ачык.",
"wlheader-showupdated": "Сезнең соңгы төзәтмәләрдән соң үзгәргән битләр <strong>калын</strong> шрифт белән күрсәтелгән.",
"wlnote": "Түбәндә $3 $4 вакыт аралыгының {{PLURAL:$2|соңгы сәгатендә|соңгы <strong>$2</strong> сәгатендә}} ясалган {{PLURAL:$1|ахыргы төзәтмә|ахыргы <strong>$1</strong> төзәтмә}} күрсәтелгән.",
"mycontris": "Кертем",
"anoncontribs": "Кертем",
"contribsub2": "Кертем {{GENDER:$3|$1}} ($2)",
+ "nocontribs": "Күрсштелгән шартларга җавап биргән үзгәрешләр таҗылмады.",
"uctop": "(хәзерге)",
"month": "Айдан башлап (һәм элегрәк):",
"year": "Елдан башлап (һәм элегрәк):",
"emaillink": "хат язу",
"blocklogpage": "Тыю көндәлеге",
"blocklogentry": "[[$1]] $2 вакытка тыелды $3",
+ "reblock-logentry": "[[$1]] тыю көләүләрен $2 $3 вакыт арасына үзгәртте",
"unblocklogentry": "$1 кулланучысының тыелу вакыты бетте",
"block-log-flags-anononly": "аноним кулланучылар гына",
"block-log-flags-nocreate": "яңа хисап язмасы теркәү тыелган",
"rcfilters-target-page-placeholder": "ایک صفحہ کا نام (یا زمرہ) درج کریں",
"rcnotefrom": "ذیل میں <strong>$2</strong> سے کی گئی {{PLURAL:$5|تبدیلی|تبدیلیاں}} <strong>$1</strong> تک دکھائی جا رہی ہیں۔",
"rclistfromreset": "انتخاب تاریخ کی ترتیب نو",
- "rclistfrom": "$2، $3ء سے ہونے والی نئی تبدیلیاں دکھائیں",
+ "rclistfrom": "$2، $3 سے ہونے والی نئی تبدیلیاں دکھائیں",
"rcshowhideminor": "معمولی ترامیم $1",
"rcshowhideminor-show": "دکھائیں",
"rcshowhideminor-hide": "چھپائیں",
"savechanges": "Lưu các thay đổi",
"publishpage": "Đăng trang",
"publishchanges": "Đăng thay đổi",
+ "savearticle-start": "Lưu trang...",
+ "savechanges-start": "Lưu thay đổi...",
+ "publishpage-start": "Đăng trang...",
+ "publishchanges-start": "Đăng thay đổi...",
"preview": "Xem trước",
"showpreview": "Xem trước",
"showdiff": "Xem thay đổi",
"tog-ccmeonemails": "ⴰⵣⵏ ⵉⵢⵉ ⴷ ⵜⵓⵏⵖⵉⵍⵉⵏ ⵏ ⵉⵎⴰⵢⵍⵏ ⵏⵏⴰ ⵓⵣⵏⵖ ⵉ ⵉⵎⵙⵙⵎⵔⵙⵏ ⵢⴰⴹⵏ",
"tog-diffonly": "ⴰⴷ ⵓⵔ ⵜⵙⵙⴽⴷ ⵜⵓⵎⴰⵢⵜ ⵏ ⵜⴰⵙⵏⴰ ⴷⴷⵓ ⵉⵎⵣⴰⵔⴰⵢⵏ",
"tog-showhiddencats": "ⵙⴽⵏ ⵜⴰⴳⴳⴰⵢⵉⵏ ⵉⵜⵜⵓⵃⴹⴰⵏ",
+ "underline-never": "ⵓⵙⴰⵔ",
"sunday": "ⴰⵙⴰⵎⴰⵙ",
"monday": "ⴰⵢⵏⴰⵙ",
"tuesday": "ⴰⵙⵉⵏⴰⵙ",
"privacypage": "Project:ⵜⴰⵙⵔⵜⵉⵜ ⵏ ⵜⵉⵏⵏⵓⵜⵍⴰ",
"ok": "ⵡⴰⵅⵅⴰ",
"retrievedfrom": "ⵉⵜⵜⵓⵙⴰⵖⵓⵍ ⵙⴳ $1",
+ "youhavenewmessages": "{{PLURAL:$3|ⵖⵓⵔⴽ}} $1 ($2).",
"youhavenewmessagesmanyusers": "ⴷⴰⵔⴽ $1 ⵙⴳ ⵎⵏⵏⴰⵡ ⵉⵎⵙⵙⵎⵔⵙⵏ ($2)",
"newmessageslinkplural": "{{PLURAL:$1|ⵜⵓⵣⵉⵏⵜ ⵜⴰⵎⴰⵢⵏⵓⵜ|999=ⵜⵓⵣⵉⵏⵉⵏ ⵜⵉⵎⴰⵢⵏⵓⵜⵉⵏ}}",
"youhavenewmessagesmulti": "ⵍⵍⴰⵏ ⵖⵓⵔⴽ ⵜⵓⵣⵉⵏⵉⵏ ⵜⵉⵎⴰⵢⵏⵓⵜⵉⵏ ⴳ $1",
"nstab-help": "ⵜⴰⵙⵏⴰ ⵏ ⵜⵡⵉⵙⵉ",
"nstab-category": "ⴰⵙⵎⵉⵍ",
"mainpage-nstab": "ⵜⴰⵙⵏⴰ ⵏ ⵓⵙⵏⵓⴱⴳ",
+ "nosuchspecialpage": "ⴰⵡⴷ ⵢⴰⵜ ⵜⴰⵙⵏⴰ ⵉⵥⵍⵉⵏ.",
+ "nospecialpagetext": "<strong>ⵜⴻⵜⵜⵔⴷ ⵢⴰⵜ ⵜⴰⵙⵏⴰ ⵉⵥⵍⵉⵏ ⵓⵔ ⵉⵅⴷⵉⵎⵏ</strong>",
"error": "ⵜⴰⵣⴳⵍⵜ",
"databaseerror-error": "ⵜⴰⵣⴳⵍⵜ: $1",
"badtitle": "ⴳⴰⵔ ⴰⵣⵡⵍ",
"pt-login-button": "ⴽⵛⵎ",
"pt-createaccount": "ⵙⵏⴼⵍⵓⵍ ⴰⵎⵉⴹⴰⵏ",
"pt-userlogout": "ⴼⴼⵖ",
+ "newpassword": "ⵜⴰⴳⵓⵔⵉ ⵏ ⵓⵣⵔⴰⵢ ⵜⴰⵎⴰⵢⵏⵓⵜ",
"botpasswords-label-create": "ⵙⵏⵓⵍⴼⵓ",
"botpasswords-label-delete": "ⴽⴽⵙ",
"passwordreset": "ⵔⴰⵔ ⴷ ⵜⴰⴳⵓⵔⵉ ⵏ ⵓⵣⵔⴰⵢ",
+ "changeemail-newemail": "ⵉⵎⴰⵢⵍ ⴰⵎⴰⵢⵏⵓ:",
+ "changeemail-none": "(ⵓⵍⴰ ⵢⴰⵏ)",
"bold_sample": "ⴰⴹⵔⵉⵙ ⴰⵣⵓⵔⴰⵔ",
"bold_tip": "ⴰⴹⵔⵉⵙ ⴰⵣⵓⵔⴰⵔ",
"italic_sample": "ⴰⴹⵔⵉⵙ ⵓⵣⵍⵉⴳ",
"lineno": "ⵉⵣⵔⵉⵔⵉ $1:",
"compareselectedversions": "ⵙⵎⵣⴰⵣⴰⵍ ⵉⵣⵣⵔⴰⵢⵏ ⵉⵜⵜⵓⵙⵜⴰⵢⵏ",
"editundo": "ⵙⵔ",
+ "diff-empty": "(ⵓⵔ ⵉⵍⵍⵉ ⵓⵎⵣⴰⵔⴰⵢ)",
"searchresults": "ⵜⵉⵢⴰⴼⵓⵜⵉⵏ ⵏ ⵓⵔⵣⵣⵓ",
"searchresults-title": "ⵜⵉⵢⴰⴼⵓⵜⵉⵏ ⵏ ⵓⵔⵣⵣⵓ ⵖⴼ \"$1\"",
"prevn": "{{PLURAL:$1|$1}} ⵉⵎⵣⵡⵓⵔⴰ",
"searchprofile-advanced-tooltip": "ⵔⵣⵓ ⴳ ⵜⵉⵔⵉⵡⵉⵏ ⵏ ⵉⵙⵎⴰⵡⵏ ⵉⵜⵡⴰⵏⵉⵎⴰⵏ",
"search-result-size": "$1 ({{PLURAL:$2|1 ⵜⴳⵓⵔⵉ|$2 ⵜⴳⵓⵔⵉⵡⵉⵏ}})",
"search-redirect": "(ⵓⵖⵓⵍ ⵙⴳ $1)",
+ "search-section": "(ⴰⵙⴱⴹⵓ $1)",
"search-suggest": "ⵉⵙ ⵜⵅⵙⴷ ⴰⴷ ⵜⵉⵏⵉⴷ: $1",
"search-interwiki-more": "(ⵓⴳⴳⴰⵔ)",
"searchall": "ⴰⴽⴽ",
"newuserlogpage": "ⴰⵔⵔⴰ ⵏ ⵉⵙⵏⴼⴰⵍⵏ ⵏ ⵉⵎⵉⴹⴰⵏⴻⵏ ⵏ ⵉⵙⵙⵎⵔⴰⵙⵏ",
"action-edit": "ⵙⵏⴼⵍ ⵜⴰⵙⵏⴰ ⴰ",
"action-createpage": "ⵙⵏⵓⵍⴼⵓ ⵜⴰⵙⵏⴰ ⴰ",
+ "action-createaccount": "ⵙⴽⵔ ⴰⵎⵉⴹⴰⵏ ⴰⴷ ⵏ ⵓⵏⵙⵙⵎⵔⵙ",
"enhancedrc-history": "ⴰⵎⵣⵔⴰⵢ",
"recentchanges": "ⵉⵙⵏⴼⵍⵏ ⵉⵎⴳⴳⵓⵔⴰ",
"recentchanges-legend": "ⵜⵉⴷⵖⵔⵉⵏ ⵏ ⵉⵙⵏⴼⵍⵏ ⵉⵎⴳⴳⵓⵔⴰ",
+ "recentchanges-summary": "ⴹⴼⵔ ⵉⵙⵏⵉⴼⵉⵍⵏ ⵉⵎⴳⴳⵓⵔⴰ ⴰⴽⴽ ⵖⴼ ⵓⵡⵉⴽⵉ ⴷⴳ ⵜⴰⵙⵏⴰ ⴰⴷ.",
"recentchanges-label-newpage": "ⵉⵙⵏⴼⵍⵓⵍ ⵓⵙⵏⴼⵍ ⴰ ⵢⴰⵜ ⵜⴰⵙⵏⴰ ⵜⴰⵎⴰⵢⵏⵓⵜ",
"recentchanges-label-minor": "ⵡⴰ ⴷ ⴰⵙⵏⴼⵍ ⵓⵎⵥⵉⵢ",
"recentchanges-label-bot": "ⴰⵙⵏⴼⵍ ⴰⴷ ⵉⵜⵡⴰⵙⴽⴰⵔ ⵙ ⵓⴱⵓⵜ",
"allpages": "ⵎⴰⵕⵕⴰ ⵜⴰⵙⵏⵉⵡⵉⵏ",
"allarticles": "ⵜⴰⵙⵏⵉⵡⵉⵏ ⴰⴽⴽ",
"allpagessubmit": "ⴷⴷⵓ",
+ "allpages-hide-redirects": "ⵙⵙⵏⵜⵍ ⵉⵙⵡⴰⵍⴰⵜⵏ",
"categories": "ⵉⵙⵎⵉⵍⵏ",
"sp-deletedcontributions-contribs": "ⵜⵓⵎⵓⵜⵉⵏ",
"listgrouprights-members": "ⵜⴰⵍⴳⴰⵎⵜ ⵏ ⵉⴳⵎⴰⵎⵏ",
+ "usermessage-editor": "ⵓⴷⵓⵙ ⵏ ⵓⵎⵢⴰⵣⴰⵏ",
"watchlist": "ⵜⴰⵍⴳⴰⵎⵜ ⵏ ⵓⴹⴼⴼⵓⵔ",
"mywatchlist": "ⵜⴰⵍⴳⴰⵎⵜ ⵏ ⵓⴹⴼⴼⵓⵔ",
"watchlistfor2": "ⵉ $1 $2",
"watch": "ⵥⵕ",
"wlshowlast": "ⵙⴽⵏ $1 ⵜⴰⵙⵔⴰⴳⵉⵏ $2 ⵓⵙⵙⴰⵏ ⵉⵎⴳⴳⵓⵔⴰ",
"watchlist-options": "ⵜⵉⴷⵖⵔⵉⵏ ⵏ ⵜⵍⴳⴰⵎⵜ ⵏ ⵓⴹⴼⴼⵓⵔ",
+ "enotif_reset": "ⴷⵔⵣ ⵜⴰⵙⵏⵉⵡⵉⵏ ⴰⴽⴽ ⵏⵏⴰ ⵜⵔⵣⴼⴷ",
"deletepage": "ⴽⴽⵙ ⵜⴰⵙⵏⴰ",
"delete-confirm": "ⴽⴽⵙ \"$1\"",
"delete-legend": "ⴽⴽⵙ",
"mycontris": "ⵜⵓⵎⵓⵜⵉⵏ",
"anoncontribs": "ⵜⵓⵎⵓⵜⵉⵏ",
"contribsub2": "ⵉ {{GENDER:$3|$1}} ($2)",
+ "uctop": "(ⴰⵎⵉⵔⴰⵏ)",
"month": "ⵙⴳ ⵡⴰⵢⵢⵓⵔ (and earlier):",
"year": "ⵙⴳ ⵓⵙⴳⴳⵯⴰⵙ (and earlier):",
"sp-contributions-newbies": "ⵙⴽⵏ ⵜⵓⵎⵓⵜⵉⵏ ⵏ ⵉⵎⵉⴹⴰⵏ ⵉⵎⴰⵢⵏⵓⵜⵏ ⴽⴰⵏ",
"sp-contributions-uploads": "ⵉⵙⴽⵜⴰⵔⵏ",
"sp-contributions-talk": "ⵎⵙⴰⵡⴰⵍ",
"sp-contributions-search": "ⵔⵣⵓ ⵖⴼ ⵜⵓⵎⵓⵜⵉⵏ",
+ "sp-contributions-username": "ⵜⴰⵏⵙⴰ ⵏ IP ⵏⵖ ⵉⵙⵎ ⵓⵎⵔⵉⵙ:",
+ "sp-contributions-toponly": "ⵙⴽⵏ ⵖⴰⵙ ⵉⵙⵏⵉⴼⵉⵍⵏ ⵉⴳⴰⵏ ⵉⵣⵣⵔⴰⵢⵏ ⵉⵎⴳⴳⵓⵔⴰ",
"sp-contributions-newonly": "ⵙⴽⵏ ⵖⴰⵙ ⵉⵙⵏⵍⵏ ⵏⵏⴰ ⵉⴳⴰⵏ ⵉⵙⵏⵓⵍⴼⵓⵜⵏ ⵏ ⵜⴰⵙⵏⴰ",
"sp-contributions-submit": "ⵔⵣⵓ",
"whatlinkshere": "ⵎⴰ ⴰⵢⴷ ⵉⵇⵇⵏⵏ ⵙ ⴷⴰ",
"whatlinkshere-page": "ⵜⴰⵙⵏⴰ:",
"linkshere": "ⵜⴰⵙⵏⵉⵡⵉⵏ ⴰⴷ ⵣⴷⵉⵏ ⵖⵔ <strong>[[:$1]]</strong>:",
"nolinkshere": "ⵓⵔ ⵍⵍⵉⵏ ⵜⴰⵙⵏⵉⵡⵉⵏ ⵉⵣⴷⵉⵏ ⵖⵔ <strong>[[:$1]]</strong>",
+ "isredirect": "ⵙⵡⴰⵍⴰ ⵜⴰⵙⵏⴰ",
+ "istemplate": "ⴰⵙⵙⵓⵎⵢ",
"isimage": "ⴰⵙⵖⵓⵏ ⵏ ⵓⴼⴰⵢⵍⵓ",
"whatlinkshere-links": "← ⵉⵙⵖⵓⵏⴻⵏ",
+ "whatlinkshere-hidetrans": "$1 ⵉⵙⵙⵓⵎⵢⵏ",
"whatlinkshere-hidelinks": "$1 ⵉⵙⵖⵓⵏⴻⵏ",
"whatlinkshere-hideimages": "$1 ⵉⵣⴷⴰⵢⵏ ⵖⵔ ⵓⴼⵉⵍⵢⵓ",
"whatlinkshere-filters": "ⵜⵉⵙⵜⵜⴰⵢⵉⵏ",
"ipbreason": "ⵜⴰⵎⵏⵜⵉⵍⵜ:",
- "ipboptions": "2 âµ\8f âµ\9câµ\99âµ\94â´°â´³âµ\89âµ\8f:2 âµ\8f âµ\9câµ\99âµ\94â´°â´³âµ\89âµ\8f,1 âµ\8f ⵡⴰâµ\99âµ\99:1 âµ\8f ⵡⴰâµ\99âµ\99,3 âµ\8f ⵡâµ\93âµ\99âµ\99â´°âµ\8f:3 âµ\8f ⵡâµ\93âµ\99âµ\99â´°âµ\8f,1 âµ\8f âµ\89âµ\8eâ´°âµ\8dâ´°âµ\99âµ\99:1 âµ\8f âµ\89âµ\8eâ´°âµ\8dâ´°âµ\99âµ\99k,2 âµ\8f âµ\89âµ\8eâ´°âµ\8dâ´°âµ\99âµ\99âµ\8f:2 âµ\8f âµ\89âµ\8eâ´°âµ\8dâ´°âµ\99âµ\99âµ\8f,1 âµ\8f ⵡⴰⵢⵢâµ\93âµ\94:1 âµ\8f ⵡⴰⵢⵢâµ\93âµ\94,3 âµ\8f ⵡⴰⵢⵢâµ\93âµ\94âµ\8f:3 âµ\8f ⵡⴰⵢⵢâµ\93âµ\94âµ\8f,6 âµ\8f ⵡⴰⵢⵢâµ\93âµ\94âµ\8f:6 âµ\8f ⵡⴰⵢⵢâµ\93âµ\94âµ\8f,1 âµ\8f âµ\93âµ\99ⴳⴳⴰâµ\99:1 âµ\8f âµ\93âµ\99ⴳⴳⴰâµ\99,indefinite:infinite",
+ "ipboptions": "2 âµ\9câµ\99âµ\94â´°â´³âµ\89âµ\8f:2 âµ\9câµ\99âµ\94â´°â´³âµ\89âµ\8f,1 ⵡⴰâµ\99âµ\99:1 ⵡⴰâµ\99âµ\99,3 ⵡâµ\93âµ\99âµ\99â´°âµ\8f:3 ⵡâµ\93âµ\99âµ\99â´°âµ\8f,1 âµ\89âµ\8eâ´°âµ\8dâ´°âµ\99âµ\99:1 âµ\89âµ\8eâ´°âµ\8dâ´°âµ\99âµ\99,2 âµ\89âµ\8eâ´°âµ\8dâ´°âµ\99âµ\99âµ\8f:2 âµ\89âµ\8eâ´°âµ\8dâ´°âµ\99âµ\99âµ\8f,1 ⵡⴰⵢⵢâµ\93âµ\94:1 ⵡⴰⵢⵢâµ\93âµ\94,3 âµ\89ⵢⵢâµ\89âµ\94âµ\8f:3 âµ\89ⵢⵢâµ\89âµ\94âµ\8f,6 âµ\89ⵢⵢâµ\89âµ\94âµ\8f:6 âµ\89ⵢⵢâµ\89âµ\94âµ\8f,1 âµ\93âµ\99ⴳⴳⴰâµ\99:1 âµ\93âµ\99ⴳⴳⴰâµ\99,â´°âµ\94âµ\93âµ\99âµ\8eâµ\89âµ\8d:â´°âµ\94âµ\93âµ\99âµ\8eâµ\89âµ\8d",
"blocklist-reason": "ⵜⴰⵎⵏⵜⵉⵍⵜ",
"blocklink": "ⴳⴷⵍ",
"contribslink": "ⵜⵓⵎⵓⵜⵉⵏ",
"movereason": "ⵜⴰⵎⵏⵜⵉⵍⵜ:",
"delete_and_move_confirm": "ⵢⴰⵀ, ⴽⴽⵙ ⵜⴰⵙⵏⴰ",
+ "export": "ⵙⵙⵓⴼⵖ ⵜⴰⵙⵏⵉⵡⵉⵏ",
"allmessagesname": "ⵉⵙⵎ",
"allmessages-language": "ⵜⵓⵜⵍⴰⵢⵜ:",
"allmessages-filter-translate": "ⵙⵙⵓⵖⵍ",
"tooltip-pt-userpage": "ⵜⴰⵙⵏⴰ ⵏ ⵓⵙⵎⵔⴰⵙ {{GENDER:|ⵏⵏⴽ|ⵏⵏⵎ}}",
"tooltip-pt-mytalk": "ⵜⴰⵙⵏⴰ {{GENDER:|ⵏⵏⴽ|ⵏⵏⵎ}} ⵏ ⵓⵎⵙⴰⵡⴰⵍ",
"tooltip-pt-preferences": "ⵉⵙⵎⵏⵢⵉⴼⵏ {{GENDER:|ⵏⵏⴽ|ⵏⵏⵎ}}",
+ "tooltip-pt-watchlist": "ⵢⴰⵜ ⵜⵍⴳⴰⵎⵜ ⵏ ⵜⴰⵙⵏⵉⵡⵉⵏ ⵏⵏⴰ ⵜⵎⵎⵓⵜⵔⴷ ⵉ ⵉⵙⵏⵉⴼⵉⵍⵏ",
"tooltip-pt-mycontris": "ⵢⴰⵜ ⵜⵍⴳⴰⵎⵜ ⵏ ⵜⵓⵎⵓⵜⵉⵏ {{GENDER:|ⵏⵏⴽ|ⵏⵏⵎ}}",
"tooltip-pt-login": "ⴰⵔⴽ ⵏⵙⵙⵔⵇⴰⴱ ⴰⵜⴽⵛⵎⵜ; ⵎⴰⵛ ⵓⵔ ⵉⴳⵉ ⵓⵣⵓⵛⵍⵍ",
"tooltip-pt-logout": "ⴼⴼⵖ",
"tooltip-save": "ⵃⴹⵓ ⵉⵙⵏⴼⴰⵍ ⵏⵏⴽ",
"tooltip-preview": "ⵣⵔ ⵣⵡⴰⵔ ⵉⵙⵏⴼⵍⵏ ⵏⴽ. ⴼⴰⴷ ⴰⴷ ⵜⵏ ⵜⵙⵓⵙⵔⴷ.",
"tooltip-diff": "ⵙⴽⵏ ⵎⴰⵏ ⵉⵙⵏⴼⴰⵍ ⵜⴳⴳⵉⴷ ⵉ ⵓⴹⵔⵉⵙ",
+ "tooltip-compareselectedversions": "ⵥⵔ ⴰⵎⵣⴰⵔⴰⵢ ⴳⵔ ⵙⵉⵏ ⵉⵣⵣⵔⴰⵢⵏ ⵉⵜⵜⵓⵙⵜⴰⵢⵏ ⵏ ⵜⴰⵙⵏⴰ ⴰⴷ",
"tooltip-watch": "ⵔⵏⵓ ⵜⴰⵙⵏⴰ ⴰ ⵉ ⵜⵍⴳⴰⵎⵜ ⵏ ⵓⴹⴼⴼⵓⵔ {{GENDER:|ⵏⵏⴽ|ⵏⵏⵎ}}",
"tooltip-rollback": "\"ⵔⴰⵔ\" ⵙⵙⵔ ⴰⵙⵏⴼⵍ ⵏⵖ ⵉⵙⵏⴼⴰⵍⵏ ⵏ ⵓⵎⴰⴷⵔⴰⵡ ⴰⵎⴳⴳⴰⵔⵓ ⴳ ⵜⴰⵙⵏⴰ ⴷ ⵙ ⵢⴰⵏ ⵓⴽⵍⵉⴽ",
"tooltip-summary": "ⴰⵔⴰ ⴽⵔⴰ ⵏ ⵓⵙⴳⵣⵍ ⵎⵥⵥⵉⵢⵏ",
"simpleantispam-label": "ⵜⵉⵎⵏⵥⵉⵜ ⵎⴳⵍ-ⴳⴰⵔⴰⵙⵎⵔⴰⵔⴰ.\nⴰⴷ <strong>ⵓⵔ</strong> ⵜⵣⵎⵎⴻⵎⴷ ⴰⵎⵢⴰ ⴳ ⵖⵉ!",
"pageinfo-title": "ⵉⵏⵖⵎⵉⵙⵏ ⵖⴼ $1",
+ "pageinfo-header-basic": "ⵉⵏⵖⵎⵉⵙⵏ ⵏ ⵜⵙⵉⵍⴰ",
"pageinfo-header-edits": "ⵙⵏⴼⵍ ⴰⵎⵣⵔⵓⵢ",
"pageinfo-header-restrictions": "ⴰⴼⵔⴰⴳ ⵏ ⵜⴰⵙⵏⴰ",
"pageinfo-display-title": "ⵙⴽⵏ ⴰⵣⵡⵍ",
"pageinfo-article-id": "ID ⵏ ⵜⴰⵙⵏⴰ",
"pageinfo-language": "ⵜⵓⵜⵍⴰⵢⵜ ⵏ ⵜⵙⵏⴰ",
+ "pageinfo-robot-index": "ⵉⵜⵜⵓⴼⵔⴰⴳ",
+ "pageinfo-robot-noindex": "ⵓⵔ ⵉⵜⵜⵓⴼⵔⴰⴳ",
"pageinfo-watchers": "ⵓⵟⵟⵓⵏ ⵏ ⵉⵎⵥⵕⴰⵢⵏ ⵏ ⵜⴰⵙⵏⴰ",
+ "pageinfo-few-watchers": "ⴷⵔⵓⵙ ⵅⴼ $1 {{PLURAL:$1|ⴰⵎⴰⵏⵏⴰⵢ|ⵉⵎⴰⵏⵏⴰⵢⵏ}}",
+ "pageinfo-redirects-name": "ⵓⵟⵟⵓⵏ ⵏ ⵉⵙⵡⴰⵍⴰⵜⵏ ⵖⵔ ⵜⴰⵙⵏⴰ ⴰⴷ",
+ "pageinfo-subpages-name": "ⵓⵟⵟⵓⵏ ⵏ ⵜⴷⵓⵙⵏⵉⵡⵉⵏ ⵏ ⵜⴰⵙⵏⴰ ⴰⴷ",
"pageinfo-firstuser": "ⴰⵎⵙⵏⵓⵍⴼⵓ ⵏ ⵜⴰⵙⵏⴰ",
"pageinfo-firsttime": "ⴰⵙⴰⴽⵓⴷ ⵏ ⵓⵙⵏⴼⵍⵓⵍ ⵏ ⵜⴰⵙⵏⴰ",
"pageinfo-lastuser": "ⴰⵎⵙⵏⴼⵍ ⴰⵎⴳⴳⴰⵔⵓ",
"pageinfo-lasttime": "ⴰⵙⴰⴽⵓⴷ ⵏ ⵓⵙⵏⴼⵍ ⴰⵎⴳⴳⴰⵔⵓ",
"pageinfo-edits": "ⵎⴰⵕⵕⴰ ⵓⵟⵟⵓⵏ ⵏ ⵉⵙⵏⴼⴰⵍⵏ",
+ "pageinfo-authors": "ⵓⵟⵟⵓⵏ ⴰⵎⵖⵔⵓⴷ ⵏ ⵉⵎⴰⵔⴰⵜⵏ ⵉⵎⵢⴰⵍⵍⴰⵏ",
+ "pageinfo-magic-words": "ⵉⵎⴽⵓⵔⴰⵔⵏ {{PLURAL:$1|ⵜⴰⴳⵓⵔⵉ|ⵜⵉⴳⵓⵔⵉⵡⵉⵏ}} ($1)",
"pageinfo-hidden-categories": "ⵏⵜⵍ {{PLURAL:$1|ⴰⵙⵎⵉⵍ|ⵉⵙⵎⵉⵍⵏ}}($1)",
"pageinfo-toolboxlink": "ⴰⵏⵖⵎⵉⵙ ⵖⴼ ⵜⴰⵙⵏⴰ",
"pageinfo-contentpage": "ⵉⵜⵜⵓⵙⵉⴹⵏ ⴰⵎ ⵜⴰⵙⵏⴰ ⵏ ⵜⵓⵎⴰⵢⵜ",
"exif-yresolution": "ⵜⵉⵙⴷⴷⵉ ⵜⴰⴱⴷⴷⴰⵢⵜ",
"exif-datetime": "ⴰⵙⴰⴽⵓⴷ ⴷ ⵡⴰⴽⵓⴷ ⵏ ⵓⵙⵏⴼⵍ ⵏ ⵓⴼⴰⵢⵍⵓ",
"exif-model": "ⴰⵏⴰⵡ ⵏ ⵜⵙⵡⵍⴰⴼⵜ",
+ "exif-software": "ⴰⵙⵖⵥⴰⵏ ⵉⵜⵜⵓⵙⵎⵔⵙⵏ",
"exif-colorspace": "ⵜⵉⵔⵉⵡⵜ ⵏ ⵓⴽⵍⵓ",
+ "exif-datetimeoriginal": "ⴰⵙⴰⴽⵓⴷ ⴷ ⵜⵉⵣⵉ ⵏ ⵓⵙⴽⴽⵉⵔ ⵏ ⵉⵙⴼⴽⴰ",
+ "exif-datetimedigitized": "ⴰⵙⴰⴽⵓⴷ ⴷ ⵜⵉⵣⵉ ⵏ ⵓⵙⵓⵟⵟⵏ",
"exif-languagecode": "ⵜⵓⵜⵍⴰⵢⵜ",
"exif-orientation-1": "ⴰⵎⴳⵏⵓ",
"exif-dc-contributor": "ⵉⵏⴰⵎⵓⵜⵏ",
"confirm-watch-button": "ⵡⴰⵅⵅⴰ",
"confirm-unwatch-button": "ⵡⴰⵅⵅⴰ",
"confirm-rollback-button": "ⵡⴰⵅⵅⴰ",
+ "imgmultipagenext": "ⵜⴰⵙⵏⴰ ⵜⵉⵏⴹⴼⵔⵜ →",
"imgmultigo": "ⴷⴷⵓ!",
"imgmultigoto": "ⴷⴷⵓ ⵖⵔ ⵜⴰⵙⵏⴰ ⴰⴷ $1",
"img-lang-default": "(ⵜⵓⵜⵍⴰⵢⵜ ⵙ ⵓⵡⵏⵓⵍ)",
"watchlisttools-clear": "ⵙⴼⴹ ⵜⴰⵍⴳⴰⵎⵜ ⵏ ⵓⴹⴼⴼⵓⵔ",
+ "watchlisttools-view": "ⵙⴽⵏ ⵉⵙⵏⵉⴼⵉⵍⵏ ⴷ ⵢⵓⵙⴰⵏ",
"watchlisttools-edit": "ⵥⵕ ⴷ ⵜⵙⵏⴼⵍⴷ ⵜⴰⵍⴳⴰⵎⵜ ⵏ ⵓⴹⴼⴼⵓⵔ",
"redirect-submit": "ⴷⴷⵓ",
+ "redirect-value": "ⴰⵣⴰⵍ",
"redirect-user": "ID ⵏ ⵓⵎⵙⵙⵎⵔⵙ",
"redirect-page": "ID ⵏ ⵜⴰⵙⵏⴰ",
"redirect-revision": "ⴰⵣⵣⵔⴰⵢ ⵏ ⵜⴰⵙⵏⴰ",
"htmlform-no": "ⵓⵀⵓ",
"htmlform-yes": "ⵢⴰⵀ",
"logentry-delete-delete": "$1 {{GENDER:$2|ⵉⴽⴽⵙ|ⵜⴽⴽⵙ}} ⵜⴰⵙⵏⴰ $3",
+ "revdelete-content-hid": "ⵜⴻⵜⵜⵓⵏⵜⴰⵍ ⵜⵓⵎⴰⵢⵜ",
"logentry-move-move": "$1 {{GENDER:$2|ⵉⵙⵎⵓⵜⵜⵉ|ⵜⵙⵎⵓⵜⵜⵉ}} ⵜⴰⵙⵏⴰ ⵙⴳ $3 ⵖⵔ $4",
"logentry-move-move-noredirect": "{{GENDER:$2|ⵉⵙⵎⵓⵜⵜⵉ}} $1 ⵜⴰⵙⵏⴰ $3 ⵖⵔ $4 ⵎⵉⵏ ⴰⴷ ⵉⴼⵍ redirect",
"logentry-newusers-create": "{{GENDER:$2|ⵉⵙⵏⴼⵍ ⵓⵏⵙⵙⵎⵔⵙ|ⵜⵙⵏⴼⵍ ⵜⵏⵙⵙⵎⵔⵙⵜ}} $1 ⴰⵎⵉⴹⴰⵏ ⵏⵙ",
"logentry-upload-upload": "{{GENDER:$2|ⵉⵙⴽⵜⵔ|ⵜⵙⴽⵜⵔ}} $1 $3",
+ "rightsnone": "(ⵓⵍⴰ ⵢⴰⵏ)",
"feedback-thanks-title": "ⵜⴰⵏⵎⵎⵉⵔⵜ!",
"searchsuggest-search": "ⵔⵣⵓ ⴳ {{SITENAME}}",
"duration-days": "$1 ⵏ {{PLURAL:$1|ⵡⴰⵙⵙ|ⵡⵓⵙⵙⴰⵏ}}",
"recentchangeslinked-feed": "相关更改",
"recentchangeslinked-toolbox": "相关更改",
"recentchangeslinked-title": "与“$1”有关的更改",
- "recentchangeslinked-summary": "输入页面名称以查看链入(或链自)相关页面的更改。(要查看分类的成员,请输入Category:分类名称)。对[[Special:Watchlist|您的监视列表]]上页面的更改以<strong>粗体</strong>显示。",
+ "recentchangeslinked-summary": "输入页面名称以查看链入(或链自)相关页面的更改。(要查看分类的成员,请输入{{ns:category}}:分类名称)。对[[Special:Watchlist|您的监视列表]]上页面的更改以<strong>粗体</strong>显示。",
"recentchangeslinked-page": "页面名称:",
"recentchangeslinked-to": "显示链到所给出的页面",
"recentchanges-page-added-to-category": "[[:$1]]已添加至分类",
"exif-copyrighted-false": "版权状态未设定",
"exif-photometricinterpretation-0": "黑白(白为0)",
"exif-photometricinterpretation-1": "黑白(黑为0)",
+ "exif-photometricinterpretation-4": "透明遮罩",
+ "exif-photometricinterpretation-5": "分隔(可能是CMYK)",
+ "exif-photometricinterpretation-32803": "色彩滤镜矩阵",
"exif-unknowndate": "未知日期",
"exif-orientation-1": "标准",
"exif-orientation-2": "水平翻转",
"watchlisttools-view": "查看相关更改",
"watchlisttools-edit": "查看并编辑监视列表",
"watchlisttools-raw": "编辑原始监视列表",
+ "hijri-calendar-m1": "穆哈兰姆月",
+ "hijri-calendar-m2": "色法尔月",
+ "hijri-calendar-m3": "赖比尔·敖外鲁月",
+ "hijri-calendar-m4": "赖比尔·阿色尼月",
+ "hijri-calendar-m5": "主马达·敖外鲁月",
+ "hijri-calendar-m6": "主马达·阿色尼月",
+ "hijri-calendar-m7": "赖哲卜月",
+ "hijri-calendar-m8": "舍尔邦月",
+ "hijri-calendar-m9": "赖买丹月",
+ "hijri-calendar-m10": "闪瓦鲁月",
+ "hijri-calendar-m11": "都尔喀尔德月",
+ "hijri-calendar-m12": "都尔黑哲月",
+ "hebrew-calendar-m1": "提斯利月",
+ "hebrew-calendar-m2": "玛西班月",
+ "hebrew-calendar-m3": "基斯流月",
+ "hebrew-calendar-m4": "提别月",
+ "hebrew-calendar-m5": "细罢特月",
+ "hebrew-calendar-m6": "亚达月",
+ "hebrew-calendar-m6a": "第一亚达月",
+ "hebrew-calendar-m6b": "第二亚达月",
+ "hebrew-calendar-m7": "尼散月",
+ "hebrew-calendar-m8": "以珥月",
+ "hebrew-calendar-m9": "西弯月",
+ "hebrew-calendar-m10": "搭模斯月",
+ "hebrew-calendar-m11": "埃波月",
+ "hebrew-calendar-m12": "以禄月",
"signature": "[[{{ns:user}}:$1|$2]]([[{{ns:user_talk}}:$1|讨论]])",
"timezone-local": "本地",
"duplicate-defaultsort": "<strong>警告:</strong>默认排序关键词“$2”覆盖了之前的默认排序关键词“$1”。",
"Laundry Machine",
"和平至上",
"Sanmosa",
- "Dongzn"
+ "Dongzn",
+ "Shangkuanlc"
]
},
"tog-underline": "底線標示連結:",
{
- "@metadata": {
- "authors": [
- "Horacewai2",
- "Kayau",
- "Mark85296341",
- "PhiLiP",
- "Shizhao",
- "Waihorace",
- "Wong128hk",
- "Yukiseaside",
- "Yuyu"
- ]
- },
- "tog-watchlisthidebots": "監視列表中隱藏機械人的編輯",
- "january": "一月",
- "february": "二月",
- "march": "三月",
- "april": "四月",
- "may_long": "五月",
- "june": "六月",
- "july": "七月",
- "august": "八月",
- "september": "九月",
- "october": "十月",
- "november": "十一月",
- "december": "十二月",
- "mytalk": "我的討論頁",
- "tagline": "從 {{SITENAME}}",
- "search": "搜尋",
- "printableversion": "可打印版",
- "permalink": "永久連接",
- "print": "打印",
- "specialpage": "特殊頁面",
- "jumpto": "跳到:",
- "jumptosearch": "搜尋",
- "aboutpage": "Project:關於我們",
- "privacy": "私隱政策",
- "privacypage": "Project:私隱政策",
- "red-link-title": "$1 (頁面不存在)",
- "nstab-special": "特殊頁面",
- "nav-login-createaccount": "登入/創造帳戶",
- "userlogin": "登入/創造帳戶",
- "editing": "正在編輯 $1",
- "rev-deleted-comment": "(註釋已除)",
- "rev-deleted-event": "(日誌已除)",
- "revdelete-suppress-text": "壓制'''只'''應用於以下的情況:\n* 不合適的個人資料\n*: ''地址、電話號碼、身份證號碼等。''",
- "editundo": "撤銷",
- "search-mwsuggest-disabled": "沒有意見",
- "prefs-help-gender": "可選:用於軟件中的性別指定。此項資料將會被公開。",
- "group-bot": "機械人",
- "group-bot-member": "機械人",
- "grouppage-bot": "{{ns:project}}:機械人",
- "recentchanges-label-bot": "這次編輯是由機械人進行",
- "rcshowhidebots": "$1機械人的編輯",
- "activeusers-hidebots": "隱藏機械人",
- "contribslink": "貢獻",
- "tooltip-search": "搜尋 {{SITENAME}}",
- "tooltip-search-go": "若是真有其頁,則進入相同名字的頁面",
- "tooltip-search-fulltext": "在此頁面內搜尋此文字",
- "tooltip-n-mainpage": "回到首頁",
- "tooltip-n-mainpage-description": "回到首頁",
- "tooltip-n-randompage": "跳到一個隨機抽取的頁面",
- "tooltip-t-print": "這個頁面的可打印版本",
- "showhidebots": "($1機械人)",
- "specialpages": "特殊頁面"
+ "@metadata": {
+ "authors": [
+ "Horacewai2",
+ "Kayau",
+ "Mark85296341",
+ "PhiLiP",
+ "Shizhao",
+ "Waihorace",
+ "Wong128hk",
+ "Yukiseaside",
+ "Yuyu",
+ "Hello903hello",
+ "Justincheng12345",
+ "LNDDYL",
+ "Liuxinyu970226",
+ "Quest for Truth"
+ ]
+ },
+ "tog-watchlisthidebots": "隱藏監視清單中機械人的編輯",
+ "january": "一月",
+ "february": "二月",
+ "march": "三月",
+ "april": "四月",
+ "may_long": "五月",
+ "june": "六月",
+ "july": "七月",
+ "august": "八月",
+ "september": "九月",
+ "october": "十月",
+ "november": "十一月",
+ "december": "十二月",
+ "mytalk": "我的討論頁",
+ "tagline": "從 {{SITENAME}}",
+ "search": "搜尋",
+ "printableversion": "可打印版",
+ "permalink": "靜態連結",
+ "print": "打印",
+ "specialpage": "特殊頁面",
+ "jumpto": "跳到:",
+ "jumptosearch": "搜尋",
+ "aboutpage": "Project:關於我們",
+ "privacy": "私隱政策",
+ "privacypage": "Project:私隱政策",
+ "red-link-title": "$1 (頁面不存在)",
+ "nstab-user": "用戶頁面",
+ "nstab-special": "特殊頁面",
+ "nstab-template": "模板",
+ "editinginterface": "<strong>警告:</strong>您正在編輯的頁面文字是用來作為軟件介面使用。更改此頁面將會影響其他用戶在此 Wiki 上看到的用戶介面。",
+ "yourname": "用戶名稱:",
+ "userlogin-yourname": "用戶名稱",
+ "nav-login-createaccount": "登入/創造帳戶",
+ "wrongpassword": "您輸入的密碼有錯誤,請再試一次。",
+ "botpasswords": "機械人密碼",
+ "botpasswords-summary": "<em>機械人密碼</em>可在不使用帳號的主要登入密碼情況下,允許透過 API 存取使用者帳號。使用機械人密碼登入的使用者權限或會有所限制。\n\n若你並非必須設定此密碼,你便不應使用此功能。任何人都不會索取你的機械人密碼。",
+ "botpasswords-disabled": "機械人密碼已停用。",
+ "botpasswords-no-central-id": "要使用機械人密碼,您必須登入帳號集中管理系統。",
+ "botpasswords-existing": "現有機械人密碼",
+ "botpasswords-createnew": "建立新機械人密碼",
+ "botpasswords-editexisting": "編輯現有機械人密碼",
+ "botpasswords-bad-appid": "機械人名稱「$1」無效。",
+ "botpasswords-insert-failed": "無法新增機械人名稱「$1」,是否早已加入?",
+ "botpasswords-update-failed": "無法刪除機械人名稱「$1」,是否早已刪除?",
+ "botpasswords-created-body": "{{GENDER:$2|使用者}}「$2」的機械人「$1」的機械人密碼已建立。",
+ "botpasswords-updated-body": "{{GENDER:$2|使用者}}「$2」的機械人「$1」的機械人密碼已更新。",
+ "botpasswords-deleted-body": "{{GENDER:$2|使用者}}「$2」的機械人「$1」的機械人密碼已刪除。",
+ "botpasswords-newpassword": "用來登入<strong>$1</strong>的新密碼為<strong>$2</strong>。<em>請記錄此密碼以供未來參考使用。</em><br>(舊式機械人的登入名稱需與最終使用者名稱相同,您亦可使用<strong>$3</strong>作為使用者名稱,<strong>$4</strong>作為密碼。)",
+ "botpasswords-restriction-failed": "機械人密碼限制已拒絕是次登入。",
+ "passwordreset-username": "用戶名稱:",
+ "editing": "正在編輯 $1",
+ "rev-deleted-comment": "(註釋已除)",
+ "rev-deleted-event": "(日誌已除)",
+ "revdelete-suppress-text": "壓制'''只'''應用於以下的情況:\n* 不合適的個人資料\n*: ''地址、電話號碼、身份證號碼等。''",
+ "editundo": "撤銷",
+ "prefs-user-pages": "用戶頁面",
+ "username": "{{GENDER:$1|用戶名稱}}:",
+ "prefs-help-gender": "可選:用於軟件中的性別指定。此項資料將會被公開。",
+ "group-user": "用戶",
+ "group-autoconfirmed": "自動確認用戶",
+ "group-bot": "機械人",
+ "group-user-member": "{{GENDER:$1|用戶}}",
+ "group-autoconfirmed-member": "{{GENDER:$1|自動確認用戶}}",
+ "group-bot-member": "機械人",
+ "grouppage-user": "{{ns:project}}:用戶",
+ "grouppage-bot": "{{ns:project}}:機械人",
+ "right-viewmyprivateinfo": "編輯自己的私隱數據(如:電子郵件位址及真實姓名)",
+ "right-editmyprivateinfo": "編輯自己的私隱數據(如:電子郵件位址及真實姓名)",
+ "action-block": "封鎖此用戶的編輯權限",
+ "recentchanges-label-bot": "此編輯由機械人執行",
+ "rcfilters-filter-bots-label": "機械人",
+ "rcfilters-filter-humans-label": "人類(非機械人)",
+ "rcshowhidebots": "$1機械人的編輯",
+ "rcshowhideliu": "$1 已註冊的用戶",
+ "rcshowhideanons": "$1 匿名用戶",
+ "upload": "上載檔案",
+ "listfiles_user": "用戶",
+ "filehist-user": "用戶",
+ "uncategorizedtemplates": "待分類模板",
+ "listusers": "用戶清單",
+ "newpages-username": "用戶名稱:",
+ "speciallogtitlelabel": "目標 (標題或用戶):",
+ "checkbox-select": "選擇: $1",
+ "emailusername": "用戶名稱:",
+ "wlshowhidebots": "機械人",
+ "blockip": "封鎖{{GENDER:$1|用戶}}",
+ "contribslink": "貢獻",
+ "blocklogtext": "這是用戶的封禁與解禁操作的日誌記錄。\n自動封禁的 IP 位址不予包含。\n請參考 [[Special:BlockList|封禁清單]] 以檢視目前的封禁。",
+ "tooltip-search": "搜尋 {{SITENAME}}",
+ "tooltip-search-go": "若是真有其頁,則進入相同名字的頁面",
+ "tooltip-search-fulltext": "在此頁面內搜尋此文字",
+ "tooltip-n-mainpage": "回到首頁",
+ "tooltip-n-mainpage-description": "回到首頁",
+ "tooltip-n-randompage": "跳到一個隨機抽取的頁面",
+ "tooltip-t-contributions": "此用戶的貢獻清單",
+ "tooltip-t-upload": "上載檔案",
+ "tooltip-t-print": "這個頁面的可打印版本",
+ "tooltip-ca-nstab-user": "檢視用戶頁面",
+ "newimages-showbots": "顯示機械人上傳的檔案",
+ "exif-rowsperstrip": "每帶行數",
+ "redirect-user": "用戶 ID",
+ "specialpages": "特殊頁面",
+ "tags-source-manual": "由使用者與機械人手動套用",
+ "logentry-managetags-activate": "$1{{GENDER:$2|已啟用}}標籤「$4」供使用者與機械人使用"
}
--- /dev/null
+<?php
+/** Ambonese Malay (Bahasa Ambon)
+ *
+ * To improve a translation please visit https://translatewiki.net
+ *
+ * @ingroup Language
+ * @file
+ *
+ */
+
+$fallback = 'id';
require_once __DIR__ . '/Maintenance.php';
+use MediaWiki\MediaWikiServices;
+
/**
* Maintenance script that reports the hostname of a replica DB server.
*
$db = $this->getDB( DB_REPLICA, $this->getOption( 'group' ) );
$host = $db->getServer();
} else {
- $lb = wfGetLB();
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
$i = $lb->getReaderIndex();
$host = $lb->getServerName( $i );
}
require_once __DIR__ . '/Maintenance.php';
+use MediaWiki\MediaWikiServices;
+
class InitEditCount extends Maintenance {
public function __construct() {
parent::__construct();
} elseif ( $this->hasOption( 'quick' ) ) {
$backgroundMode = false;
} else {
- $backgroundMode = wfGetLB()->getServerCount() > 1;
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+ $backgroundMode = $lb->getServerCount() > 1;
}
$actorQuery = ActorMigration::newMigration()->getJoin( 'rev_user' );
</script>
<script>
// Mock startup.js
- var mwPerformance = { mark: function () {} },
- mwNow = Date.now;
+ var mwNow = Date.now;
function startUp() {
mw.config = new mw.Map();
require_once __DIR__ . '/Maintenance.php';
+use MediaWiki\MediaWikiServices;
+
/**
* Maintenance script to show database lag.
*
}
public function execute() {
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
if ( $this->hasOption( 'r' ) ) {
- $lb = wfGetLB();
echo 'time ';
$serverCount = $lb->getServerCount();
sleep( 5 );
}
} else {
- $lb = wfGetLB();
$lags = $lb->getLagTimes();
foreach ( $lags as $i => $lag ) {
$name = $lb->getServerName( $i );
-- The URL of the file api.php
iw_api nvarchar(max) NOT NULL,
- -- The name of the database (for a connection to be established with wfGetLB( 'wikiid' ))
+ -- The name of the database (for a connection to be established with LBFactory::getMainLB( 'wikiid' ))
iw_wikiid nvarchar(64) NOT NULL,
-- A boolean value indicating whether the wiki is in this project
"{$prefix}_len IS NULL",
$dbr->makeList( [
"{$prefix}_len = 0",
- "{$prefix}_sha1 != \"phoiac9h4m842xq45sp7s6u21eteeq1\"", // sha1( "" )
+ "{$prefix}_sha1 != " . $dbr->addQuotes( 'phoiac9h4m842xq45sp7s6u21eteeq1' ), // sha1( "" )
], IDatabase::LIST_AND )
], IDatabase::LIST_OR )
],
ALTER TABLE archive
DROP COLUMN ar_text,
DROP COLUMN ar_flags,
- ALTER COLUMN ar_text_id SET DEFAULT 0;
+ ALTER COLUMN ar_text_id SET DEFAULT 0,
ALTER COLUMN ar_text_id SET NOT NULL;
-- The URL of the file api.php
iw_api blob NOT NULL,
- -- The name of the database (for a connection to be established with wfGetLB( 'wikiid' ))
+ -- The name of the database (for a connection to be established with LBFactory::getMainLB( 'wikiid' ))
iw_wikiid varchar(64) NOT NULL,
-- A boolean value indicating whether the wiki is in this project
require_once __DIR__ . '/Maintenance.php';
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\DBReplicationWaitError;
+
/**
* Maintenance script to update cached special pages.
*
* mysql connection to "go away"
*/
private function reopenAndWaitForReplicas() {
- if ( !wfGetLB()->pingAll() ) {
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $lb = $lbFactory->getMainLB();
+ if ( !$lb->pingAll() ) {
$this->output( "\n" );
do {
$this->error( "Connection failed, reconnecting in 10 seconds..." );
sleep( 10 );
- } while ( !wfGetLB()->pingAll() );
+ } while ( !$lb->pingAll() );
$this->output( "Reconnected\n\n" );
}
- # Wait for the replica DB to catch up
- wfWaitForSlaves();
+ // Wait for the replica DB to catch up
+ try {
+ $lbFactory->waitForReplication();
+ } catch ( DBReplicationWaitError $e ) {
+ // ignore
+ }
}
public function doSpecialPageCacheUpdates( $dbw ) {
"doc": "jsduck",
"postdoc": "grunt copy:jsduck",
"selenium": "./tests/selenium/selenium.sh",
- "selenium-test": "grunt webdriver:test"
+ "selenium-test": "wdio ./tests/selenium/wdio.conf.js"
},
"devDependencies": {
"bluebird": "3.5.1",
"grunt-jsonlint": "1.1.0",
"grunt-karma": "2.0.0",
"grunt-stylelint": "0.10.0",
- "grunt-webdriver": "2.0.3",
"karma": "1.7.1",
"karma-chrome-launcher": "2.2.0",
"karma-firefox-launcher": "1.0.1",
],
],
+ 'jquery.tablesorter.styles' => [
+ 'targets' => [ 'desktop', 'mobile' ],
+ 'styles' => [
+ 'resources/src/jquery/jquery.tablesorter.styles.less',
+ ],
+ ],
+ 'jquery.makeCollapsible.styles' => [
+ 'targets' => [ 'desktop', 'mobile' ],
+ 'class' => ResourceLoaderLessVarFileModule::class,
+ 'styles' => [
+ 'resources/src/jquery/jquery.makeCollapsible.styles.less',
+ ],
+ ],
+
'mediawiki.skinning.content.parsoid' => [
// Style Parsoid HTML+RDFa output consistent with wikitext from PHP parser
// with the interface.css styles; skinStyles should be used if your
'scripts' => 'resources/src/jquery/jquery.localize.js',
],
'jquery.makeCollapsible' => [
+ 'dependencies' => [ 'jquery.makeCollapsible.styles' ],
'scripts' => 'resources/src/jquery/jquery.makeCollapsible.js',
'styles' => 'resources/src/jquery/jquery.makeCollapsible.css',
'messages' => [ 'collapsible-expand', 'collapsible-collapse' ],
'styles' => 'resources/src/jquery/jquery.tablesorter.less',
'messages' => [ 'sort-descending', 'sort-ascending' ],
'dependencies' => [
+ 'jquery.tablesorter.styles',
'mediawiki.RegExp',
'mediawiki.language.months',
],
'moment' => [
'scripts' => [
// HACK: For some reason if you don't define window.moment first, loading moment fatals
- 'resources/src/moment-global.js',
+ 'resources/src/moment/moment-global.js',
'resources/lib/moment/moment.js',
],
'languageScripts' => [
'de-ch' => 'resources/lib/moment/locale/de-ch.js',
'dv' => 'resources/lib/moment/locale/dv.js',
'el' => 'resources/lib/moment/locale/el.js',
- 'en' => 'resources/src/moment-dmy.js',
+ 'en' => 'resources/src/moment/moment-dmy.js',
'en-au' => 'resources/lib/moment/locale/en-au.js',
'en-ca' => 'resources/lib/moment/locale/en-ca.js',
'en-gb' => 'resources/lib/moment/locale/en-gb.js',
// after locale definitions
'skinScripts' => [
'default' => [
- 'resources/src/moment-locale-overrides.js',
+ 'resources/src/moment/moment-locale-overrides.js',
],
],
'dependencies' => [
'mediawiki.api',
],
],
- 'mediawiki.sectionAnchor' => [
- // Back-compat to hide it on cached pages (T18691; Ie9e334e973; 2015-03-17)
- 'styles' => 'resources/src/mediawiki/mediawiki.sectionAnchor.css',
- 'targets' => [ 'desktop', 'mobile' ],
- ],
'mediawiki.storage' => [
'scripts' => 'resources/src/mediawiki/mediawiki.storage.js',
'targets' => [ 'desktop', 'mobile' ],
],
'mediawiki.libs.pluralruleparser' => [
- 'scripts' => 'resources/src/mediawiki.libs/CLDRPluralRuleParser.js',
+ 'scripts' => [
+ 'resources/lib/CLDRPluralRuleParser/CLDRPluralRuleParser.js',
+ 'resources/src/mediawiki.libs.pluralruleparser/export.js',
+ ],
'targets' => [ 'desktop', 'mobile' ],
],
/* MediaWiki Libs */
'mediawiki.libs.jpegmeta' => [
- 'scripts' => 'resources/src/mediawiki.libs/mediawiki.libs.jpegmeta.js',
+ 'scripts' => [
+ 'resources/src/mediawiki.libs.jpegmeta/jpegmeta.js',
+ 'resources/src/mediawiki.libs.jpegmeta/export.js',
+ ],
'targets' => [ 'desktop', 'mobile' ],
],
--- /dev/null
+/**
+ * cldrpluralparser.js
+ * A parser engine for CLDR plural rules.
+ *
+ * Copyright 2012-2014 Santhosh Thottingal and other contributors
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ *
+ * @version 0.1.0
+ * @source https://github.com/santhoshtr/CLDRPluralRuleParser
+ * @author Santhosh Thottingal <santhosh.thottingal@gmail.com>
+ * @author Timo Tijhof
+ * @author Amir Aharoni
+ */
+
+/**
+ * Evaluates a plural rule in CLDR syntax for a number
+ * @param {string} rule
+ * @param {integer} number
+ * @return {boolean} true if evaluation passed, false if evaluation failed.
+ */
+
+// UMD returnExports https://github.com/umdjs/umd/blob/master/returnExports.js
+(function(root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(factory);
+ } else if (typeof exports === 'object') {
+ // Node. Does not work with strict CommonJS, but
+ // only CommonJS-like environments that support module.exports,
+ // like Node.
+ module.exports = factory();
+ } else {
+ // Browser globals (root is window)
+ root.pluralRuleParser = factory();
+ }
+}(this, function() {
+
+function pluralRuleParser(rule, number) {
+ 'use strict';
+
+ /*
+ Syntax: see http://unicode.org/reports/tr35/#Language_Plural_Rules
+ -----------------------------------------------------------------
+ condition = and_condition ('or' and_condition)*
+ ('@integer' samples)?
+ ('@decimal' samples)?
+ and_condition = relation ('and' relation)*
+ relation = is_relation | in_relation | within_relation
+ is_relation = expr 'is' ('not')? value
+ in_relation = expr (('not')? 'in' | '=' | '!=') range_list
+ within_relation = expr ('not')? 'within' range_list
+ expr = operand (('mod' | '%') value)?
+ operand = 'n' | 'i' | 'f' | 't' | 'v' | 'w'
+ range_list = (range | value) (',' range_list)*
+ value = digit+
+ digit = 0|1|2|3|4|5|6|7|8|9
+ range = value'..'value
+ samples = sampleRange (',' sampleRange)* (',' ('…'|'...'))?
+ sampleRange = decimalValue '~' decimalValue
+ decimalValue = value ('.' value)?
+ */
+
+ // We don't evaluate the samples section of the rule. Ignore it.
+ rule = rule.split('@')[0].replace(/^\s*/, '').replace(/\s*$/, '');
+
+ if (!rule.length) {
+ // Empty rule or 'other' rule.
+ return true;
+ }
+
+ // Indicates the current position in the rule as we parse through it.
+ // Shared among all parsing functions below.
+ var pos = 0,
+ operand,
+ expression,
+ relation,
+ result,
+ whitespace = makeRegexParser(/^\s+/),
+ value = makeRegexParser(/^\d+/),
+ _n_ = makeStringParser('n'),
+ _i_ = makeStringParser('i'),
+ _f_ = makeStringParser('f'),
+ _t_ = makeStringParser('t'),
+ _v_ = makeStringParser('v'),
+ _w_ = makeStringParser('w'),
+ _is_ = makeStringParser('is'),
+ _isnot_ = makeStringParser('is not'),
+ _isnot_sign_ = makeStringParser('!='),
+ _equal_ = makeStringParser('='),
+ _mod_ = makeStringParser('mod'),
+ _percent_ = makeStringParser('%'),
+ _not_ = makeStringParser('not'),
+ _in_ = makeStringParser('in'),
+ _within_ = makeStringParser('within'),
+ _range_ = makeStringParser('..'),
+ _comma_ = makeStringParser(','),
+ _or_ = makeStringParser('or'),
+ _and_ = makeStringParser('and');
+
+ function debug() {
+ // console.log.apply(console, arguments);
+ }
+
+ debug('pluralRuleParser', rule, number);
+
+ // Try parsers until one works, if none work return null
+ function choice(parserSyntax) {
+ return function() {
+ var i, result;
+
+ for (i = 0; i < parserSyntax.length; i++) {
+ result = parserSyntax[i]();
+
+ if (result !== null) {
+ return result;
+ }
+ }
+
+ return null;
+ };
+ }
+
+ // Try several parserSyntax-es in a row.
+ // All must succeed; otherwise, return null.
+ // This is the only eager one.
+ function sequence(parserSyntax) {
+ var i, parserRes,
+ originalPos = pos,
+ result = [];
+
+ for (i = 0; i < parserSyntax.length; i++) {
+ parserRes = parserSyntax[i]();
+
+ if (parserRes === null) {
+ pos = originalPos;
+
+ return null;
+ }
+
+ result.push(parserRes);
+ }
+
+ return result;
+ }
+
+ // Run the same parser over and over until it fails.
+ // Must succeed a minimum of n times; otherwise, return null.
+ function nOrMore(n, p) {
+ return function() {
+ var originalPos = pos,
+ result = [],
+ parsed = p();
+
+ while (parsed !== null) {
+ result.push(parsed);
+ parsed = p();
+ }
+
+ if (result.length < n) {
+ pos = originalPos;
+
+ return null;
+ }
+
+ return result;
+ };
+ }
+
+ // Helpers - just make parserSyntax out of simpler JS builtin types
+ function makeStringParser(s) {
+ var len = s.length;
+
+ return function() {
+ var result = null;
+
+ if (rule.substr(pos, len) === s) {
+ result = s;
+ pos += len;
+ }
+
+ return result;
+ };
+ }
+
+ function makeRegexParser(regex) {
+ return function() {
+ var matches = rule.substr(pos).match(regex);
+
+ if (matches === null) {
+ return null;
+ }
+
+ pos += matches[0].length;
+
+ return matches[0];
+ };
+ }
+
+ /**
+ * Integer digits of n.
+ */
+ function i() {
+ var result = _i_();
+
+ if (result === null) {
+ debug(' -- failed i', parseInt(number, 10));
+
+ return result;
+ }
+
+ result = parseInt(number, 10);
+ debug(' -- passed i ', result);
+
+ return result;
+ }
+
+ /**
+ * Absolute value of the source number (integer and decimals).
+ */
+ function n() {
+ var result = _n_();
+
+ if (result === null) {
+ debug(' -- failed n ', number);
+
+ return result;
+ }
+
+ result = parseFloat(number, 10);
+ debug(' -- passed n ', result);
+
+ return result;
+ }
+
+ /**
+ * Visible fractional digits in n, with trailing zeros.
+ */
+ function f() {
+ var result = _f_();
+
+ if (result === null) {
+ debug(' -- failed f ', number);
+
+ return result;
+ }
+
+ result = (number + '.').split('.')[1] || 0;
+ debug(' -- passed f ', result);
+
+ return result;
+ }
+
+ /**
+ * Visible fractional digits in n, without trailing zeros.
+ */
+ function t() {
+ var result = _t_();
+
+ if (result === null) {
+ debug(' -- failed t ', number);
+
+ return result;
+ }
+
+ result = (number + '.').split('.')[1].replace(/0$/, '') || 0;
+ debug(' -- passed t ', result);
+
+ return result;
+ }
+
+ /**
+ * Number of visible fraction digits in n, with trailing zeros.
+ */
+ function v() {
+ var result = _v_();
+
+ if (result === null) {
+ debug(' -- failed v ', number);
+
+ return result;
+ }
+
+ result = (number + '.').split('.')[1].length || 0;
+ debug(' -- passed v ', result);
+
+ return result;
+ }
+
+ /**
+ * Number of visible fraction digits in n, without trailing zeros.
+ */
+ function w() {
+ var result = _w_();
+
+ if (result === null) {
+ debug(' -- failed w ', number);
+
+ return result;
+ }
+
+ result = (number + '.').split('.')[1].replace(/0$/, '').length || 0;
+ debug(' -- passed w ', result);
+
+ return result;
+ }
+
+ // operand = 'n' | 'i' | 'f' | 't' | 'v' | 'w'
+ operand = choice([n, i, f, t, v, w]);
+
+ // expr = operand (('mod' | '%') value)?
+ expression = choice([mod, operand]);
+
+ function mod() {
+ var result = sequence(
+ [operand, whitespace, choice([_mod_, _percent_]), whitespace, value]
+ );
+
+ if (result === null) {
+ debug(' -- failed mod');
+
+ return null;
+ }
+
+ debug(' -- passed ' + parseInt(result[0], 10) + ' ' + result[2] + ' ' + parseInt(result[4], 10));
+
+ return parseInt(result[0], 10) % parseInt(result[4], 10);
+ }
+
+ function not() {
+ var result = sequence([whitespace, _not_]);
+
+ if (result === null) {
+ debug(' -- failed not');
+
+ return null;
+ }
+
+ return result[1];
+ }
+
+ // is_relation = expr 'is' ('not')? value
+ function is() {
+ var result = sequence([expression, whitespace, choice([_is_]), whitespace, value]);
+
+ if (result !== null) {
+ debug(' -- passed is : ' + result[0] + ' == ' + parseInt(result[4], 10));
+
+ return result[0] === parseInt(result[4], 10);
+ }
+
+ debug(' -- failed is');
+
+ return null;
+ }
+
+ // is_relation = expr 'is' ('not')? value
+ function isnot() {
+ var result = sequence(
+ [expression, whitespace, choice([_isnot_, _isnot_sign_]), whitespace, value]
+ );
+
+ if (result !== null) {
+ debug(' -- passed isnot: ' + result[0] + ' != ' + parseInt(result[4], 10));
+
+ return result[0] !== parseInt(result[4], 10);
+ }
+
+ debug(' -- failed isnot');
+
+ return null;
+ }
+
+ function not_in() {
+ var i, range_list,
+ result = sequence([expression, whitespace, _isnot_sign_, whitespace, rangeList]);
+
+ if (result !== null) {
+ debug(' -- passed not_in: ' + result[0] + ' != ' + result[4]);
+ range_list = result[4];
+
+ for (i = 0; i < range_list.length; i++) {
+ if (parseInt(range_list[i], 10) === parseInt(result[0], 10)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ debug(' -- failed not_in');
+
+ return null;
+ }
+
+ // range_list = (range | value) (',' range_list)*
+ function rangeList() {
+ var result = sequence([choice([range, value]), nOrMore(0, rangeTail)]),
+ resultList = [];
+
+ if (result !== null) {
+ resultList = resultList.concat(result[0]);
+
+ if (result[1][0]) {
+ resultList = resultList.concat(result[1][0]);
+ }
+
+ return resultList;
+ }
+
+ debug(' -- failed rangeList');
+
+ return null;
+ }
+
+ function rangeTail() {
+ // ',' range_list
+ var result = sequence([_comma_, rangeList]);
+
+ if (result !== null) {
+ return result[1];
+ }
+
+ debug(' -- failed rangeTail');
+
+ return null;
+ }
+
+ // range = value'..'value
+ function range() {
+ var i, array, left, right,
+ result = sequence([value, _range_, value]);
+
+ if (result !== null) {
+ debug(' -- passed range');
+
+ array = [];
+ left = parseInt(result[0], 10);
+ right = parseInt(result[2], 10);
+
+ for (i = left; i <= right; i++) {
+ array.push(i);
+ }
+
+ return array;
+ }
+
+ debug(' -- failed range');
+
+ return null;
+ }
+
+ function _in() {
+ var result, range_list, i;
+
+ // in_relation = expr ('not')? 'in' range_list
+ result = sequence(
+ [expression, nOrMore(0, not), whitespace, choice([_in_, _equal_]), whitespace, rangeList]
+ );
+
+ if (result !== null) {
+ debug(' -- passed _in:' + result);
+
+ range_list = result[5];
+
+ for (i = 0; i < range_list.length; i++) {
+ if (parseInt(range_list[i], 10) === parseInt(result[0], 10)) {
+ return (result[1][0] !== 'not');
+ }
+ }
+
+ return (result[1][0] === 'not');
+ }
+
+ debug(' -- failed _in ');
+
+ return null;
+ }
+
+ /**
+ * The difference between "in" and "within" is that
+ * "in" only includes integers in the specified range,
+ * while "within" includes all values.
+ */
+ function within() {
+ var range_list, result;
+
+ // within_relation = expr ('not')? 'within' range_list
+ result = sequence(
+ [expression, nOrMore(0, not), whitespace, _within_, whitespace, rangeList]
+ );
+
+ if (result !== null) {
+ debug(' -- passed within');
+
+ range_list = result[5];
+
+ if ((result[0] >= parseInt(range_list[0], 10)) &&
+ (result[0] < parseInt(range_list[range_list.length - 1], 10))) {
+
+ return (result[1][0] !== 'not');
+ }
+
+ return (result[1][0] === 'not');
+ }
+
+ debug(' -- failed within ');
+
+ return null;
+ }
+
+ // relation = is_relation | in_relation | within_relation
+ relation = choice([is, not_in, isnot, _in, within]);
+
+ // and_condition = relation ('and' relation)*
+ function and() {
+ var i,
+ result = sequence([relation, nOrMore(0, andTail)]);
+
+ if (result) {
+ if (!result[0]) {
+ return false;
+ }
+
+ for (i = 0; i < result[1].length; i++) {
+ if (!result[1][i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ debug(' -- failed and');
+
+ return null;
+ }
+
+ // ('and' relation)*
+ function andTail() {
+ var result = sequence([whitespace, _and_, whitespace, relation]);
+
+ if (result !== null) {
+ debug(' -- passed andTail' + result);
+
+ return result[3];
+ }
+
+ debug(' -- failed andTail');
+
+ return null;
+
+ }
+ // ('or' and_condition)*
+ function orTail() {
+ var result = sequence([whitespace, _or_, whitespace, and]);
+
+ if (result !== null) {
+ debug(' -- passed orTail: ' + result[3]);
+
+ return result[3];
+ }
+
+ debug(' -- failed orTail');
+
+ return null;
+ }
+
+ // condition = and_condition ('or' and_condition)*
+ function condition() {
+ var i,
+ result = sequence([and, nOrMore(0, orTail)]);
+
+ if (result) {
+ for (i = 0; i < result[1].length; i++) {
+ if (result[1][i]) {
+ return true;
+ }
+ }
+
+ return result[0];
+ }
+
+ return false;
+ }
+
+ result = condition();
+
+ /**
+ * For success, the pos must have gotten to the end of the rule
+ * and returned a non-null.
+ * n.b. This is part of language infrastructure,
+ * so we do not throw an internationalizable message.
+ */
+ if (result === null) {
+ throw new Error('Parse error at position ' + pos.toString() + ' for rule: ' + rule);
+ }
+
+ if (pos !== rule.length) {
+ debug('Warning: Rule not parsed completely. Parser stopped at ' + rule.substr(0, pos) + ' for rule: ' + rule);
+ }
+
+ return result;
+}
+
+return pluralRuleParser;
+
+}));
* I717f2580e Avoid deprecated jQuery.expr.filters.
+jquery.ui.mouse.js
+* Ia49ad6470 Avoid deprecated jQuery.fn.bind().
+* Ia49ad6470 Avoid deprecated jQuery.fn.unbind().
+
+
jquery.ui.widget.js
* I7ffbfd2e5 Avoid deprecated jQuery.expr[":"].
* I717f2580e Avoid deprecated jQuery.fn.bind().
var that = this;
this.element
- .bind('mousedown.'+this.widgetName, function(event) {
+ .on('mousedown.'+this.widgetName, function(event) {
return that._mouseDown(event);
})
- .bind('click.'+this.widgetName, function(event) {
+ .on('click.'+this.widgetName, function(event) {
if (true === $.data(event.target, that.widgetName + '.preventClickEvent')) {
$.removeData(event.target, that.widgetName + '.preventClickEvent');
event.stopImmediatePropagation();
// TODO: make sure destroying one instance of mouse doesn't mess with
// other instances of mouse
_mouseDestroy: function() {
- this.element.unbind('.'+this.widgetName);
+ this.element.off('.'+this.widgetName);
if ( this._mouseMoveDelegate ) {
$(document)
- .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
- .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+ .off('mousemove.'+this.widgetName, this._mouseMoveDelegate)
+ .off('mouseup.'+this.widgetName, this._mouseUpDelegate);
}
},
return that._mouseUp(event);
};
$(document)
- .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
- .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+ .on('mousemove.'+this.widgetName, this._mouseMoveDelegate)
+ .on('mouseup.'+this.widgetName, this._mouseUpDelegate);
event.preventDefault();
_mouseUp: function(event) {
$(document)
- .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
- .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+ .off('mousemove.'+this.widgetName, this._mouseMoveDelegate)
+ .off('mouseup.'+this.widgetName, this._mouseUpDelegate);
if (this._mouseStarted) {
this._mouseStarted = false;
/*!
- * QUnit 2.4.0
+ * QUnit 2.6.0
* https://qunitjs.com/
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license
* https://jquery.org/license
*
- * Date: 2017-07-08T15:20Z
+ * Date: 2018-03-27T02:18Z
*/
/** Font Family and Sizes */
/*!
- * QUnit 2.4.0
+ * QUnit 2.6.0
* https://qunitjs.com/
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license
* https://jquery.org/license
*
- * Date: 2017-07-08T15:20Z
+ * Date: 2018-03-27T02:18Z
*/
(function (global$1) {
'use strict';
- global$1 = global$1 && 'default' in global$1 ? global$1['default'] : global$1;
+ global$1 = global$1 && global$1.hasOwnProperty('default') ? global$1['default'] : global$1;
var window = global$1.window;
var self$1 = global$1.self;
var priorityCount = 0;
var unitSampler = void 0;
+ // This is a queue of functions that are tasks within a single test.
+ // After tests are dequeued from config.queue they are expanded into
+ // a set of tasks in this queue.
+ var taskQueue = [];
+
/**
- * Advances the ProcessingQueue to the next item if it is ready.
- * @param {Boolean} last
+ * Advances the taskQueue to the next task. If the taskQueue is empty,
+ * process the testQueue
*/
function advance() {
+ advanceTaskQueue();
+
+ if (!taskQueue.length) {
+ advanceTestQueue();
+ }
+ }
+
+ /**
+ * Advances the taskQueue to the next task if it is ready and not empty.
+ */
+ function advanceTaskQueue() {
var start = now();
config.depth = (config.depth || 0) + 1;
- while (config.queue.length && !config.blocking) {
+ while (taskQueue.length && !config.blocking) {
var elapsedTime = now() - start;
if (!defined.setTimeout || config.updateRate <= 0 || elapsedTime < config.updateRate) {
- if (priorityCount > 0) {
- priorityCount--;
- }
-
- config.queue.shift()();
+ var task = taskQueue.shift();
+ task();
} else {
- setTimeout(advance, 13);
+ setTimeout(advance);
break;
}
}
config.depth--;
+ }
+ /**
+ * Advance the testQueue to the next test to process. Call done() if testQueue completes.
+ */
+ function advanceTestQueue() {
if (!config.blocking && !config.queue.length && config.depth === 0) {
done();
+ return;
}
- }
- function addToQueueImmediate(callback) {
- if (objectType(callback) === "array") {
- while (callback.length) {
- addToQueueImmediate(callback.pop());
- }
+ var testTasks = config.queue.shift();
+ addToTaskQueue(testTasks());
- return;
+ if (priorityCount > 0) {
+ priorityCount--;
}
- config.queue.unshift(callback);
- priorityCount++;
+ advance();
+ }
+
+ /**
+ * Enqueue the tasks for a test into the task queue.
+ * @param {Array} tasksArray
+ */
+ function addToTaskQueue(tasksArray) {
+ taskQueue.push.apply(taskQueue, toConsumableArray(tasksArray));
}
/**
- * Adds a function to the ProcessingQueue for execution.
- * @param {Function|Array} callback
- * @param {Boolean} priority
+ * Return the number of tasks remaining in the task queue to be processed.
+ * @return {Number}
+ */
+ function taskQueueLength() {
+ return taskQueue.length;
+ }
+
+ /**
+ * Adds a test to the TestQueue for execution.
+ * @param {Function} testTasksFunc
+ * @param {Boolean} prioritize
* @param {String} seed
*/
- function addToQueue(callback, prioritize, seed) {
+ function addToTestQueue(testTasksFunc, prioritize, seed) {
if (prioritize) {
- config.queue.splice(priorityCount++, 0, callback);
+ config.queue.splice(priorityCount++, 0, testTasksFunc);
} else if (seed) {
if (!unitSampler) {
unitSampler = unitSamplerGenerator(seed);
// Insert into a random position after all prioritized items
var index = Math.floor(unitSampler() * (config.queue.length - priorityCount + 1));
- config.queue.splice(priorityCount + index, 0, callback);
+ config.queue.splice(priorityCount + index, 0, testTasksFunc);
} else {
- config.queue.push(callback);
+ config.queue.push(testTasksFunc);
}
}
var runtime = now() - config.started;
var passed = config.stats.all - config.stats.bad;
+ if (config.stats.all === 0) {
+
+ if (config.filter && config.filter.length) {
+ throw new Error("No tests matched the filter \"" + config.filter + "\".");
+ }
+
+ if (config.module && config.module.length) {
+ throw new Error("No tests matched the module \"" + config.module + "\".");
+ }
+
+ if (config.moduleId && config.moduleId.length) {
+ throw new Error("No tests matched the moduleId \"" + config.moduleId + "\".");
+ }
+
+ if (config.testId && config.testId.length) {
+ throw new Error("No tests matched the testId \"" + config.testId + "\".");
+ }
+
+ throw new Error("No tests were run.");
+ }
+
emit("runEnd", globalSuite.end(true));
runLoggingCallbacks("done", {
passed: passed,
var ProcessingQueue = {
finished: false,
- add: addToQueue,
- addImmediate: addToQueueImmediate,
- advance: advance
+ add: addToTestQueue,
+ advance: advance,
+ taskCount: taskQueueLength
};
var TestReport = function () {
this.async = false;
this.expected = 0;
} else {
+ if (typeof this.callback !== "function") {
+ var method = this.todo ? "todo" : "test";
+
+ // eslint-disable-next-line max-len
+ throw new TypeError("You must provide a function as a test callback to QUnit." + method + "(\"" + settings.testName + "\")");
+ }
+
this.assert = new Assert(this);
}
}
_this.preserveEnvironment = true;
}
- if (hookName === "after" && hookOwner.unskippedTestsRun !== numberOfUnskippedTests(hookOwner) - 1 && config.queue.length > 2) {
+ // The 'after' hook should only execute when there are not tests left and
+ // when the 'after' and 'finish' tasks are the only tasks left to process
+ if (hookName === "after" && hookOwner.unskippedTestsRun !== numberOfUnskippedTests(hookOwner) - 1 && (config.queue.length > 0 || ProcessingQueue.taskCount() > 2)) {
return;
}
finish: function finish() {
config.current = this;
+
+ if (this.steps.length) {
+ var stepsList = this.steps.join(", ");
+ this.pushFailure("Expected assert.verifySteps() to be called before end of test " + ("after using assert.step(). Unverified steps: " + stepsList), this.stack);
+ }
+
if (config.requireExpects && this.expected === null) {
this.pushFailure("Expected number of assertions to be defined, but expect() was " + "not called.", this.stack);
} else if (this.expected !== null && this.expected !== this.assertions.length) {
}
function runTest() {
-
- // Each of these can by async
- ProcessingQueue.addImmediate([function () {
+ return [function () {
test.before();
- }, test.hooks("before"), function () {
+ }].concat(toConsumableArray(test.hooks("before")), [function () {
test.preserveTestEnvironment();
- }, test.hooks("beforeEach"), function () {
+ }], toConsumableArray(test.hooks("beforeEach")), [function () {
test.run();
- }, test.hooks("afterEach").reverse(), test.hooks("after").reverse(), function () {
+ }], toConsumableArray(test.hooks("afterEach").reverse()), toConsumableArray(test.hooks("after").reverse()), [function () {
test.after();
}, function () {
test.finish();
pushResult: function pushResult(resultInfo) {
if (this !== config.current) {
- throw new Error("Assertion occured after test had finished.");
+ throw new Error("Assertion occurred after test had finished.");
}
// Destructure of resultInfo = { result, actual, expected, message, negative }
result: resultInfo.result,
message: resultInfo.message,
actual: resultInfo.actual,
- expected: resultInfo.expected,
testId: this.testId,
negative: resultInfo.negative || false,
runtime: now() - this.started,
todo: !!this.todo
};
+ if (hasOwn.call(resultInfo, "expected")) {
+ details.expected = resultInfo.expected;
+ }
+
if (!resultInfo.result) {
source = resultInfo.source || sourceFromStacktrace();
result: false,
message: message || "error",
actual: actual || null,
- expected: null,
source: source
});
},
then = promise.then;
if (objectType(then) === "function") {
resume = internalStop(test);
- then.call(promise, function () {
- resume();
- }, function (error) {
- message = "Promise rejected " + (!phase ? "during" : phase.replace(/Each$/, "")) + " \"" + test.testName + "\": " + (error && error.message || error);
- test.pushFailure(message, extractStacktrace(error, 0));
-
- // Else next test will carry the responsibility
- saveGlobal();
-
- // Unblock
- resume();
- });
+ if (config.notrycatch) {
+ then.call(promise, function () {
+ resume();
+ });
+ } else {
+ then.call(promise, function () {
+ resume();
+ }, function (error) {
+ message = "Promise rejected " + (!phase ? "during" : phase.replace(/Each$/, "")) + " \"" + test.testName + "\": " + (error && error.message || error);
+ test.pushFailure(message, extractStacktrace(error, 0));
+
+ // Else next test will carry the responsibility
+ saveGlobal();
+
+ // Unblock
+ internalRecover(test);
+ });
+ }
}
}
},
}
begin();
- }, 13);
+ });
} else {
begin();
}
}, {
key: "step",
value: function step(message) {
+ var assertionMessage = message;
var result = !!message;
this.test.steps.push(message);
+ if (objectType(message) === "undefined" || message === "") {
+ assertionMessage = "You must provide a message to assert.step";
+ } else if (objectType(message) !== "string") {
+ assertionMessage = "You must provide a string value to assert.step";
+ result = false;
+ }
+
return this.pushResult({
result: result,
- message: message || "You must provide a message to assert.step"
+ message: assertionMessage
});
}
}, {
key: "verifySteps",
value: function verifySteps(steps, message) {
- this.deepEqual(this.test.steps, steps, message);
+
+ // Since the steps array is just string values, we can clone with slice
+ var actualStepsClone = this.test.steps.slice();
+ this.deepEqual(actualStepsClone, steps, message);
+ this.test.steps.length = 0;
}
// Specify the number of expected assertions to guarantee that failed test
message: message
});
}
+ }, {
+ key: "rejects",
+ value: function rejects(promise, expected, message) {
+ var result = false;
+
+ var currentTest = this instanceof Assert && this.test || config.current;
+
+ // 'expected' is optional unless doing string comparison
+ if (objectType(expected) === "string") {
+ if (message === undefined) {
+ message = expected;
+ expected = undefined;
+ } else {
+ message = "assert.rejects does not accept a string value for the expected " + "argument.\nUse a non-string object value (e.g. validator function) instead " + "if necessary.";
+
+ currentTest.assert.pushResult({
+ result: false,
+ message: message
+ });
+
+ return;
+ }
+ }
+
+ var then = promise && promise.then;
+ if (objectType(then) !== "function") {
+ var _message = "The value provided to `assert.rejects` in " + "\"" + currentTest.testName + "\" was not a promise.";
+
+ currentTest.assert.pushResult({
+ result: false,
+ message: _message,
+ actual: promise
+ });
+
+ return;
+ }
+
+ var done = this.async();
+
+ return then.call(promise, function handleFulfillment() {
+ var message = "The promise returned by the `assert.rejects` callback in " + "\"" + currentTest.testName + "\" did not reject.";
+
+ currentTest.assert.pushResult({
+ result: false,
+ message: message,
+ actual: promise
+ });
+
+ done();
+ }, function handleRejection(actual) {
+ var expectedType = objectType(expected);
+
+ // We don't want to validate
+ if (expected === undefined) {
+ result = true;
+ expected = actual;
+
+ // Expected is a regexp
+ } else if (expectedType === "regexp") {
+ result = expected.test(errorString(actual));
+
+ // Expected is a constructor, maybe an Error constructor
+ } else if (expectedType === "function" && actual instanceof expected) {
+ result = true;
+
+ // Expected is an Error object
+ } else if (expectedType === "object") {
+ result = actual instanceof expected.constructor && actual.name === expected.name && actual.message === expected.message;
+
+ // Expected is a validation function which returns true if validation passed
+ } else {
+ if (expectedType === "function") {
+ result = expected.call({}, actual) === true;
+ expected = null;
+
+ // Expected is some other invalid type
+ } else {
+ result = false;
+ message = "invalid expected value provided to `assert.rejects` " + "callback in \"" + currentTest.testName + "\": " + expectedType + ".";
+ }
+ }
+
+ currentTest.assert.pushResult({
+ result: result,
+ actual: actual,
+ expected: expected,
+ message: message
+ });
+
+ done();
+ });
+ }
}]);
return Assert;
}();
return false;
}
+ // Handle an unhandled rejection
+ function onUnhandledRejection(reason) {
+ var resultInfo = {
+ result: false,
+ message: reason.message || "error",
+ actual: reason,
+ source: reason.stack || sourceFromStacktrace(3)
+ };
+
+ var currentTest = config.current;
+ if (currentTest) {
+ currentTest.assert.pushResult(resultInfo);
+ } else {
+ test("global failure", extend(function (assert) {
+ assert.pushResult(resultInfo);
+ }, { validTest: true }));
+ }
+ }
+
var focused = false;
var QUnit = {};
var globalSuite = new SuiteReport();
QUnit.isLocal = !(defined.document && window.location.protocol !== "file:");
// Expose the current QUnit version
- QUnit.version = "2.4.0";
+ QUnit.version = "2.6.0";
function createModule(name, testEnvironment, modifiers) {
var parentModule = moduleStack.length ? moduleStack.slice(-1)[0] : null;
return sourceFromStacktrace(offset);
},
- onError: onError
+ onError: onError,
+
+ onUnhandledRejection: onUnhandledRejection
});
QUnit.pushFailure = pushFailure;
if (defined.setTimeout) {
setTimeout(function () {
begin();
- }, 13);
+ });
} else {
begin();
}
var fixture = document.getElementById("qunit-fixture");
if (fixture) {
- config.fixture = fixture.innerHTML;
+ config.fixture = fixture.cloneNode(true);
}
}
}
var fixture = document.getElementById("qunit-fixture");
- if (fixture) {
- fixture.innerHTML = config.fixture;
+ var resetFixtureType = _typeof(config.fixture);
+ if (resetFixtureType === "string") {
+
+ // support user defined values for `config.fixture`
+ var newFixture = document.createElement("div");
+ newFixture.setAttribute("id", "qunit-fixture");
+ newFixture.innerHTML = config.fixture;
+ fixture.parentNode.replaceChild(newFixture, fixture);
+ } else {
+ var clonedFixture = config.fixture.cloneNode(true);
+ fixture.parentNode.replaceChild(clonedFixture, fixture);
}
}
// Skip inherited or undefined properties
if (hasOwn.call(params, key) && params[key] !== undefined) {
- // Output a parameter for each value of this key (but usually just one)
+ // Output a parameter for each value of this key
+ // (but usually just one)
arrValue = [].concat(params[key]);
for (i = 0; i < arrValue.length; i++) {
querystring += encodeURIComponent(key);
if (config.altertitle && document$$1.title) {
// Show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
+ // use escape sequences in case file gets loaded with non-utf-8
+ // charset
document$$1.title = [stats.failedTests ? "\u2716" : "\u2714", document$$1.title.replace(/^[\u2714\u2716] /i, "")].join(" ");
}
if (running) {
bad = QUnit.config.reorder && details.previousFailure;
- running.innerHTML = (bad ? "Rerunning previously failed test: <br />" : "Running: <br />") + getNameHtml(details.name, details.module);
+ running.innerHTML = [bad ? "Rerunning previously failed test: <br />" : "Running: <br />", getNameHtml(details.name, details.module)].join("");
}
});
return ret;
};
+
+ // Listen for unhandled rejections, and call QUnit.onUnhandledRejection
+ window.addEventListener("unhandledrejection", function (event) {
+ QUnit.onUnhandledRejection(event.reason);
+ });
})();
/*
line = text.substring(lineStart, lineEnd + 1);
lineStart = lineEnd + 1;
- if (lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : lineHash[line] !== undefined) {
+ var lineHashExists = lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : lineHash[line] !== undefined;
+
+ if (lineHashExists) {
chars += String.fromCharCode(lineHash[line]);
} else {
chars += String.fromCharCode(lineArrayLength);
+/*
+ * Please do not add any CSS rules here that impact the positioning of the element
+ * e.g. padding, margin, position or float.
+ * These instead should live in jquery.makeCollapsible.styles
+*/
+
/* See also jquery.makeCollapsible.js */
.mw-collapsible-toggle {
float: right;
.mw-collapsible-toggle-default:after {
content: ']';
}
-/* Align the toggle based on the direction of the content language */
-/* @noflip */
-.mw-content-ltr .mw-collapsible-toggle,
-.mw-content-rtl .mw-content-ltr .mw-collapsible-toggle {
- float: right;
-}
-/* @noflip */
-.mw-content-rtl .mw-collapsible-toggle,
-.mw-content-ltr .mw-content-rtl .mw-collapsible-toggle {
- float: left;
-}
.mw-customtoggle,
.mw-collapsible-toggle {
.mw-content-ltr .mw-content-rtl caption .mw-collapsible-toggle {
float: none;
}
-
-/* list-items go as wide as their parent element, don't float them inside list items */
-li .mw-collapsible-toggle,
-.mw-content-ltr li .mw-collapsible-toggle,
-.mw-content-rtl li .mw-collapsible-toggle,
-.mw-content-rtl .mw-content-ltr li .mw-collapsible-toggle,
-.mw-content-ltr .mw-content-rtl li .mw-collapsible-toggle {
- float: none;
-}
-
-/* the added list item should have no list-style */
-.mw-collapsible-toggle-li {
- list-style: none;
-}
/**
* jQuery makeCollapsible
+ * Note: To avoid performance issues such as reflows, several styles are
+ * shipped in mediawiki.makeCollapsible.styles to reserve space for the toggle control. Please
+ * familiarise yourself with that CSS before making any changes to this code.
*
* Dual licensed:
* - CC BY 3.0 <http://creativecommons.org/licenses/by/3.0>
if ( $collapsible.data( 'mw-made-collapsible' ) ) {
return;
} else {
- $collapsible.data( 'mw-made-collapsible', true );
+ // Let CSS know that it no longer needs to worry about flash of unstyled content.
+ // This will allow mediawiki.makeCollapsible.styles to disable temporary pseudo elements, that
+ // are needed to avoid a flash of unstyled content.
+ $collapsible.addClass( 'mw-made-collapsible' )
+ .data( 'mw-made-collapsible', true );
}
// Use custom text or default?
--- /dev/null
+/**
+ * These rules prevent re-flows relating to collapsible on-wiki elements (T42812).
+ * This is done by temporarily creating a pseudo element in the place that JavaScript will insert
+ * a toggle control. The same CSS rules that control the positioning of the toggle control will apply
+ * to the pseudo element. When the JavaScript has executed
+ * (See corresponding non-render blocking CSS in jquery.makeCollapsible)
+ * all pseudo elements will be removed.
+ *
+ * Currently we support all the examples on [[mw:Manual:Collapsible_elements/Demo/Simple]]
+ * All examples on [[mw:Manual:Collapsible_elements/Demo/Advanced]] are supported with the following
+ * exceptions
+ * - Custom collapsible 4 (table-row)
+ * -- CSS selector would be too complicated
+ * - Collapsible div nested in collapsed div
+ * -- Given it's not easy to identify the collapsed content via CSS, text will be shown until
+ * JavaScript has loaded
+ * - "Combination example"
+ * -- At a later time, we may want to support the use of of `attr`, but given the code
+ * complexity we will not for the time being (see https://davidwalsh.name/css-content-attr)
+ */
+
+// This selector is used frequently in the code to indicate that the JavaScript has successfully completed
+// it's execution and pseudo elements can be disabled. For readability and maintainability it is separated
+// as a LESS variable.
+@exclude: ~'.mw-made-collapsible';
+
+.client-js {
+
+ ol.mw-collapsible:before,
+ ul.mw-collapsible:before,
+ .mw-collapsible-toggle-li {
+ /*
+ Rather than inherit any margins from the the general li selector - make sure this is explicit
+ to avoid reflows
+ */
+ display: list-item;
+ list-style: none;
+ margin-bottom: 0.1em;
+ }
+
+ // Reset when mw-collapsible-toggle-li is rendered
+ ol.mw-made-collapsible:before,
+ ul.mw-made-collapsible:before {
+ display: none;
+ }
+
+ ol.mw-collapsible:not( @{exclude} ):before,
+ ul.mw-collapsible:not( @{exclude} ):before,
+ // Where the tbody or thead is the first child of the collapsible table
+ table.mw-collapsible:not( @{exclude} ) :first-child tr:first-child th:last-child:before,
+ table.mw-collapsible:not( @{exclude} ) > caption:first-child:after {
+ content: '[@{msg-collapsible-collapse}]';
+ }
+
+ td.mw-collapsed:not( @{exclude} ):before,
+ table.mw-collapsed:not( @{exclude} ) :first-child tr:first-child th:last-child:before,
+ table.mw-collapsed:not( @{exclude} ) > caption:first-child:after,
+ div.mw-collapsed:not( @{exclude} ):before {
+ content: '[@{msg-collapsible-expand}]';
+ }
+
+ // Any element with id beginning `mw-customcollapsible` will have special treatment
+ .mw-collapsible[ id^='mw-customcollapsible' ] th:before,
+ .mw-collapsible[ id^='mw-customcollapsible' ]:before {
+ content: none !important; // stylelint-disable-line declaration-no-important
+ }
+
+ // Special case for table where first child is caption element
+ table.mw-collapsible:not( @{exclude} ) > caption:first-child:after {
+ float: none;
+ display: block;
+ }
+
+ // Use the exclude selector to ensure animations do not break
+ .mw-collapsed:not( @{exclude} ) {
+ // Avoid FOUC/reflows on collapsed elements by making sure they are opened by default (T42812)
+ > p,
+ > table,
+ // Manual:Collapsible_elements/Demo/Simple#Collapsed_by_default
+ > thead + tbody,
+ tr:not( :first-child ),
+ .mw-collapsible-content {
+ display: none;
+ }
+ }
+}
+
+/* Align the toggle based on the direction of the content language */
+/* @noflip */
+.mw-content-ltr,
+.mw-content-rtl .mw-content-ltr {
+ .mw-collapsible:not( @{exclude} ) th:before,
+ .mw-collapsible:not( @{exclude} ):before,
+ .mw-collapsible-toggle {
+ float: right;
+ }
+}
+
+/* @noflip */
+.mw-content-rtl,
+.mw-content-ltr .mw-content-rtl {
+ .mw-collapsible:not( @{exclude} ) th:before,
+ .mw-collapsible:not( @{exclude} ):before,
+ .mw-collapsible-toggle {
+ float: left;
+ }
+}
+
+/* list-items go as wide as their parent element, don't float them inside list items */
+li,
+.mw-content-ltr li,
+.mw-content-rtl li,
+.mw-content-ltr .mw-content-rtl li,
+.mw-content-rtl .mw-content-ltr li {
+ .mw-collapsible-toggle {
+ float: none;
+ }
+}
+
+// special treatment for list items to match above
+// !important necessary to override overly-specific float left and right above.
+ol.mw-collapsible:not( @{exclude} ):before,
+ul.mw-collapsible:not( @{exclude} ):before {
+ float: none !important; // stylelint-disable-line declaration-no-important
+}
return;
}
}
- $table.addClass( 'jquery-tablesorter' );
+ // The `sortable` class is used to identify tables which will become sortable
+ // If not used it will create a FOUC but it should be added since the sortable class
+ // is responsible for certain crucial style elements. If the class is already present
+ // this action will be harmless.
+ $table.addClass( 'jquery-tablesorter sortable' );
// Merge and extend
config = $.extend( {}, $.tablesorter.defaultOptions, settings );
cursor: pointer;
background-repeat: no-repeat;
background-position: center right;
- padding-right: 21px;
+ // Note: To avoid reflows, a padding is set in
+ // the jquery.tableSorter.styles module as a render blocking style.
+ // Please do not add any CSS rules here that impact the positioning of the element
+ // e.g. padding, margin, position or float.
}
th.headerSortUp {
--- /dev/null
+.client-js {
+ // Reserve space for table sortable controls
+ table.sortable th {
+ padding-right: 21px;
+ }
+}
border-radius: 0 0 2px 2px;
}
- .editButtons .oo-ui-buttonInputWidget,
+ // Use buttonElement to include ButtonInputWidget and ButtonWidget
+ .editButtons .oo-ui-buttonElement,
.cancelLink,
.editHelp {
margin-top: 0.5em;
--- /dev/null
+/* global JpegMeta */
+( function ( mw ) {
+
+ // Export as module
+ module.exports = function ( fileReaderResult, fileName ) {
+ return new JpegMeta.JpegFile( fileReaderResult, fileName );
+ };
+
+ // Back-compat: Also expose via mw.lib
+ // @deprecated since 1.31
+ mw.log.deprecate( mw.libs, 'jpegmeta', module.exports );
+}( mediaWiki ) );
--- /dev/null
+/**
+ * This is JsJpegMeta v1.0
+ * From: https://code.google.com/p/jsjpegmeta/downloads/list
+ * From: https://github.com/bennoleslie/jsjpegmeta/blob/v1.0.0/jpegmeta.js
+ *
+ * Ported to MediaWiki ResourceLoader by Bryan Tong Minh
+ * Changes:
+ * - Add closure.
+ * - Add this.JpegMeta assignment to expose it as global.
+ */
+
+( function () {
+ /*
+ Copyright (c) 2009 Ben Leslie
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+ /*
+ This JavaScript library is used to parse meta-data from files
+ with mime-type image/jpeg.
+
+ Include it with something like:
+
+ <script type="text/javascript" src="jpegmeta.js"></script>
+
+ This adds a single 'module' object called 'JpegMeta' to the global
+ namespace.
+
+ Public Functions
+ ----------------
+ JpegMeta.parseNum - parse unsigned integers from binary data
+ JpegMeta.parseSnum - parse signed integers from binary data
+
+ Public Classes
+ --------------
+ JpegMeta.Rational - A rational number class
+ JpegMeta.JfifSegment
+ JpegMeta.ExifSegment
+ JpegMeta.JpegFile - Primary class for Javascript parsing
+ */
+
+ var JpegMeta = {};
+ // MediaWiki: Expose as global
+ this.JpegMeta = JpegMeta;
+
+ /*
+ parse an unsigned number of size bytes at offset in some binary string data.
+ If endian
+ is "<" parse the data as little endian, if endian
+ is ">" parse as big-endian.
+ */
+ JpegMeta.parseNum = function parseNum(endian, data, offset, size) {
+ var i;
+ var ret;
+ var big_endian = (endian === ">");
+ if (offset === undefined) offset = 0;
+ if (size === undefined) size = data.length - offset;
+ for (big_endian ? i = offset : i = offset + size - 1;
+ big_endian ? i < offset + size : i >= offset;
+ big_endian ? i++ : i--) {
+ ret <<= 8;
+ ret += data.charCodeAt(i);
+ }
+ return ret;
+ };
+
+ /*
+ parse an signed number of size bytes at offset in some binary string data.
+ If endian
+ is "<" parse the data as little endian, if endian
+ is ">" parse as big-endian.
+ */
+ JpegMeta.parseSnum = function parseSnum(endian, data, offset, size) {
+ var i;
+ var ret;
+ var neg;
+ var big_endian = (endian === ">");
+ if (offset === undefined) offset = 0;
+ if (size === undefined) size = data.length - offset;
+ for (big_endian ? i = offset : i = offset + size - 1;
+ big_endian ? i < offset + size : i >= offset;
+ big_endian ? i++ : i--) {
+ if (neg === undefined) {
+ /* Negative if top bit is set */
+ neg = (data.charCodeAt(i) & 0x80) === 0x80;
+ }
+ ret <<= 8;
+ /* If it is negative we invert the bits */
+ ret += neg ? ~data.charCodeAt(i) & 0xff: data.charCodeAt(i);
+ }
+ if (neg) {
+ /* If it is negative we do two's complement */
+ ret += 1;
+ ret *= -1;
+ }
+ return ret;
+ };
+
+ /* Rational number class */
+ JpegMeta.Rational = function Rational(num, den)
+ {
+ this.num = num;
+ this.den = den || 1;
+ return this;
+ };
+
+ /* Rational number methods */
+ JpegMeta.Rational.prototype.toString = function toString() {
+ if (this.num === 0) {
+ return "" + this.num;
+ }
+ if (this.den === 1) {
+ return "" + this.num;
+ }
+ if (this.num === 1) {
+ return this.num + " / " + this.den;
+ }
+ return this.num / this.den; // + "/" + this.den;
+ };
+
+ JpegMeta.Rational.prototype.asFloat = function asFloat() {
+ return this.num / this.den;
+ };
+
+ /* MetaGroup class */
+ JpegMeta.MetaGroup = function MetaGroup(fieldName, description) {
+ this.fieldName = fieldName;
+ this.description = description;
+ this.metaProps = {};
+ return this;
+ };
+
+ JpegMeta.MetaGroup.prototype._addProperty = function _addProperty(fieldName, description, value) {
+ var property = new JpegMeta.MetaProp(fieldName, description, value);
+ this[property.fieldName] = property;
+ this.metaProps[property.fieldName] = property;
+ };
+
+ JpegMeta.MetaGroup.prototype.toString = function toString() {
+ return "[MetaGroup " + this.description + "]";
+ };
+
+ /* MetaProp class */
+ JpegMeta.MetaProp = function MetaProp(fieldName, description, value) {
+ this.fieldName = fieldName;
+ this.description = description;
+ this.value = value;
+ return this;
+ };
+
+ JpegMeta.MetaProp.prototype.toString = function toString() {
+ return "" + this.value;
+ };
+
+ /* JpegFile class */
+ JpegMeta.JpegFile = function JpegFile(binary_data, filename) {
+ /* Change this to EOI if we want to parse. */
+ var break_segment = this._SOS;
+
+ this.metaGroups = {};
+ this._binary_data = binary_data;
+ this.filename = filename;
+
+ /* Go through and parse. */
+ var pos = 0;
+ var pos_start_of_segment = 0;
+ var delim;
+ var mark;
+ var _mark;
+ var segsize;
+ var headersize;
+ var mark_code;
+ var mark_fn;
+
+ /* Check to see if this looks like a JPEG file */
+ if (this._binary_data.slice(0, 2) !== this._SOI_MARKER) {
+ throw new Error("Doesn't look like a JPEG file. First two bytes are " +
+ this._binary_data.charCodeAt(0) + "," +
+ this._binary_data.charCodeAt(1) + ".");
+ }
+
+ pos += 2;
+
+ while (pos < this._binary_data.length) {
+ delim = this._binary_data.charCodeAt(pos++);
+ mark = this._binary_data.charCodeAt(pos++);
+
+ pos_start_of_segment = pos;
+
+ if (delim != this._DELIM) {
+ break;
+ }
+
+ if (mark === break_segment) {
+ break;
+ }
+
+ headersize = JpegMeta.parseNum(">", this._binary_data, pos, 2);
+
+ /* Find the end */
+ pos += headersize;
+ while (pos < this._binary_data.length) {
+ delim = this._binary_data.charCodeAt(pos++);
+ if (delim == this._DELIM) {
+ _mark = this._binary_data.charCodeAt(pos++);
+ if (_mark != 0x0) {
+ pos -= 2;
+ break;
+ }
+ }
+ }
+
+ segsize = pos - pos_start_of_segment;
+
+ if (this._markers[mark]) {
+ mark_code = this._markers[mark][0];
+ mark_fn = this._markers[mark][1];
+ } else {
+ mark_code = "UNKN";
+ mark_fn = undefined;
+ }
+
+ if (mark_fn) {
+ this[mark_fn](mark, pos_start_of_segment + 2);
+ }
+
+ }
+
+ if (this.general === undefined) {
+ throw Error("Invalid JPEG file.");
+ }
+
+ return this;
+ };
+
+ this.JpegMeta.JpegFile.prototype.toString = function () {
+ return "[JpegFile " + this.filename + " " +
+ this.general.type + " " +
+ this.general.pixelWidth + "x" +
+ this.general.pixelHeight +
+ " Depth: " + this.general.depth + "]";
+ };
+
+ /* Some useful constants */
+ this.JpegMeta.JpegFile.prototype._SOI_MARKER = '\xff\xd8';
+ this.JpegMeta.JpegFile.prototype._DELIM = 0xff;
+ this.JpegMeta.JpegFile.prototype._EOI = 0xd9;
+ this.JpegMeta.JpegFile.prototype._SOS = 0xda;
+
+ this.JpegMeta.JpegFile.prototype._sofHandler = function _sofHandler (mark, pos) {
+ if (this.general !== undefined) {
+ throw Error("Unexpected multiple-frame image");
+ }
+
+ this._addMetaGroup("general", "General");
+ this.general._addProperty("depth", "Depth", JpegMeta.parseNum(">", this._binary_data, pos, 1));
+ this.general._addProperty("pixelHeight", "Pixel Height", JpegMeta.parseNum(">", this._binary_data, pos + 1, 2));
+ this.general._addProperty("pixelWidth", "Pixel Width",JpegMeta.parseNum(">", this._binary_data, pos + 3, 2));
+ this.general._addProperty("type", "Type", this._markers[mark][2]);
+ };
+
+ /* JFIF idents */
+ this.JpegMeta.JpegFile.prototype._JFIF_IDENT = "JFIF\x00";
+ this.JpegMeta.JpegFile.prototype._JFXX_IDENT = "JFXX\x00";
+
+ /* Exif idents */
+ this.JpegMeta.JpegFile.prototype._EXIF_IDENT = "Exif\x00";
+
+ /* TIFF types */
+ this.JpegMeta.JpegFile.prototype._types = {
+ /* The format is identifier : ["type name", type_size_in_bytes ] */
+ 1 : ["BYTE", 1],
+ 2 : ["ASCII", 1],
+ 3 : ["SHORT", 2],
+ 4 : ["LONG", 4],
+ 5 : ["RATIONAL", 8],
+ 6 : ["SBYTE", 1],
+ 7 : ["UNDEFINED", 1],
+ 8 : ["SSHORT", 2],
+ 9 : ["SLONG", 4],
+ 10 : ["SRATIONAL", 8],
+ 11 : ["FLOAT", 4],
+ 12 : ["DOUBLE", 8]
+ };
+
+ this.JpegMeta.JpegFile.prototype._tifftags = {
+ /* A. Tags relating to image data structure */
+ 256 : ["Image width", "ImageWidth"],
+ 257 : ["Image height", "ImageLength"],
+ 258 : ["Number of bits per component", "BitsPerSample"],
+ 259 : ["Compression scheme", "Compression",
+ {1 : "uncompressed", 6 : "JPEG compression" }],
+ 262 : ["Pixel composition", "PhotmetricInerpretation",
+ {2 : "RGB", 6 : "YCbCr"}],
+ 274 : ["Orientation of image", "Orientation",
+ /* FIXME: Check the mirror-image / reverse encoding and rotation */
+ {1 : "Normal", 2 : "Reverse?",
+ 3 : "Upside-down", 4 : "Upside-down Reverse",
+ 5 : "90 degree CW", 6 : "90 degree CW reverse",
+ 7 : "90 degree CCW", 8 : "90 degree CCW reverse"}],
+ 277 : ["Number of components", "SamplesPerPixel"],
+ 284 : ["Image data arrangement", "PlanarConfiguration",
+ {1 : "chunky format", 2 : "planar format"}],
+ 530 : ["Subsampling ratio of Y to C", "YCbCrSubSampling"],
+ 531 : ["Y and C positioning", "YCbCrPositioning",
+ {1 : "centered", 2 : "co-sited"}],
+ 282 : ["X Resolution", "XResolution"],
+ 283 : ["Y Resolution", "YResolution"],
+ 296 : ["Resolution Unit", "ResolutionUnit",
+ {2 : "inches", 3 : "centimeters"}],
+ /* B. Tags realting to recording offset */
+ 273 : ["Image data location", "StripOffsets"],
+ 278 : ["Number of rows per strip", "RowsPerStrip"],
+ 279 : ["Bytes per compressed strip", "StripByteCounts"],
+ 513 : ["Offset to JPEG SOI", "JPEGInterchangeFormat"],
+ 514 : ["Bytes of JPEG Data", "JPEGInterchangeFormatLength"],
+ /* C. Tags relating to image data characteristics */
+ 301 : ["Transfer function", "TransferFunction"],
+ 318 : ["White point chromaticity", "WhitePoint"],
+ 319 : ["Chromaticities of primaries", "PrimaryChromaticities"],
+ 529 : ["Color space transformation matrix coefficients", "YCbCrCoefficients"],
+ 532 : ["Pair of black and white reference values", "ReferenceBlackWhite"],
+ /* D. Other tags */
+ 306 : ["Date and time", "DateTime"],
+ 270 : ["Image title", "ImageDescription"],
+ 271 : ["Make", "Make"],
+ 272 : ["Model", "Model"],
+ 305 : ["Software", "Software"],
+ 315 : ["Person who created the image", "Artist"],
+ 316 : ["Host Computer", "HostComputer"],
+ 33432 : ["Copyright holder", "Copyright"],
+
+ 34665 : ["Exif tag", "ExifIfdPointer"],
+ 34853 : ["GPS tag", "GPSInfoIfdPointer"]
+ };
+
+ this.JpegMeta.JpegFile.prototype._exiftags = {
+ /* Tag Support Levels (2) - 0th IFX Exif Private Tags */
+ /* A. Tags Relating to Version */
+ 36864 : ["Exif Version", "ExifVersion"],
+ 40960 : ["FlashPix Version", "FlashpixVersion"],
+
+ /* B. Tag Relating to Image Data Characteristics */
+ 40961 : ["Color Space", "ColorSpace"],
+
+ /* C. Tags Relating to Image Configuration */
+ 37121 : ["Meaning of each component", "ComponentsConfiguration"],
+ 37122 : ["Compressed Bits Per Pixel", "CompressedBitsPerPixel"],
+ 40962 : ["Pixel X Dimension", "PixelXDimension"],
+ 40963 : ["Pixel Y Dimension", "PixelYDimension"],
+
+ /* D. Tags Relating to User Information */
+ 37500 : ["Manufacturer notes", "MakerNote"],
+ 37510 : ["User comments", "UserComment"],
+
+ /* E. Tag Relating to Related File Information */
+ 40964 : ["Related audio file", "RelatedSoundFile"],
+
+ /* F. Tags Relating to Date and Time */
+ 36867 : ["Date Time Original", "DateTimeOriginal"],
+ 36868 : ["Date Time Digitized", "DateTimeDigitized"],
+ 37520 : ["DateTime subseconds", "SubSecTime"],
+ 37521 : ["DateTimeOriginal subseconds", "SubSecTimeOriginal"],
+ 37522 : ["DateTimeDigitized subseconds", "SubSecTimeDigitized"],
+
+ /* G. Tags Relating to Picture-Taking Conditions */
+ 33434 : ["Exposure time", "ExposureTime"],
+ 33437 : ["FNumber", "FNumber"],
+ 34850 : ["Exposure program", "ExposureProgram"],
+ 34852 : ["Spectral sensitivity", "SpectralSensitivity"],
+ 34855 : ["ISO Speed Ratings", "ISOSpeedRatings"],
+ 34856 : ["Optoelectric coefficient", "OECF"],
+ 37377 : ["Shutter Speed", "ShutterSpeedValue"],
+ 37378 : ["Aperture Value", "ApertureValue"],
+ 37379 : ["Brightness", "BrightnessValue"],
+ 37380 : ["Exposure Bias Value", "ExposureBiasValue"],
+ 37381 : ["Max Aperture Value", "MaxApertureValue"],
+ 37382 : ["Subject Distance", "SubjectDistance"],
+ 37383 : ["Metering Mode", "MeteringMode"],
+ 37384 : ["Light Source", "LightSource"],
+ 37385 : ["Flash", "Flash"],
+ 37386 : ["Focal Length", "FocalLength"],
+ 37396 : ["Subject Area", "SubjectArea"],
+ 41483 : ["Flash Energy", "FlashEnergy"],
+ 41484 : ["Spatial Frequency Response", "SpatialFrequencyResponse"],
+ 41486 : ["Focal Plane X Resolution", "FocalPlaneXResolution"],
+ 41487 : ["Focal Plane Y Resolution", "FocalPlaneYResolution"],
+ 41488 : ["Focal Plane Resolution Unit", "FocalPlaneResolutionUnit"],
+ 41492 : ["Subject Location", "SubjectLocation"],
+ 41493 : ["Exposure Index", "ExposureIndex"],
+ 41495 : ["Sensing Method", "SensingMethod"],
+ 41728 : ["File Source", "FileSource"],
+ 41729 : ["Scene Type", "SceneType"],
+ 41730 : ["CFA Pattern", "CFAPattern"],
+ 41985 : ["Custom Rendered", "CustomRendered"],
+ 41986 : ["Exposure Mode", "Exposure Mode"],
+ 41987 : ["White Balance", "WhiteBalance"],
+ 41988 : ["Digital Zoom Ratio", "DigitalZoomRatio"],
+ 41990 : ["Scene Capture Type", "SceneCaptureType"],
+ 41991 : ["Gain Control", "GainControl"],
+ 41992 : ["Contrast", "Contrast"],
+ 41993 : ["Saturation", "Saturation"],
+ 41994 : ["Sharpness", "Sharpness"],
+ 41995 : ["Device settings description", "DeviceSettingDescription"],
+ 41996 : ["Subject distance range", "SubjectDistanceRange"],
+
+ /* H. Other Tags */
+ 42016 : ["Unique image ID", "ImageUniqueID"],
+
+ 40965 : ["Interoperability tag", "InteroperabilityIFDPointer"]
+ };
+
+ this.JpegMeta.JpegFile.prototype._gpstags = {
+ /* A. Tags Relating to GPS */
+ 0 : ["GPS tag version", "GPSVersionID"],
+ 1 : ["North or South Latitude", "GPSLatitudeRef"],
+ 2 : ["Latitude", "GPSLatitude"],
+ 3 : ["East or West Longitude", "GPSLongitudeRef"],
+ 4 : ["Longitude", "GPSLongitude"],
+ 5 : ["Altitude reference", "GPSAltitudeRef"],
+ 6 : ["Altitude", "GPSAltitude"],
+ 7 : ["GPS time (atomic clock)", "GPSTimeStamp"],
+ 8 : ["GPS satellites usedd for measurement", "GPSSatellites"],
+ 9 : ["GPS receiver status", "GPSStatus"],
+ 10 : ["GPS mesaurement mode", "GPSMeasureMode"],
+ 11 : ["Measurement precision", "GPSDOP"],
+ 12 : ["Speed unit", "GPSSpeedRef"],
+ 13 : ["Speed of GPS receiver", "GPSSpeed"],
+ 14 : ["Reference for direction of movement", "GPSTrackRef"],
+ 15 : ["Direction of movement", "GPSTrack"],
+ 16 : ["Reference for direction of image", "GPSImgDirectionRef"],
+ 17 : ["Direction of image", "GPSImgDirection"],
+ 18 : ["Geodetic survey data used", "GPSMapDatum"],
+ 19 : ["Reference for latitude of destination", "GPSDestLatitudeRef"],
+ 20 : ["Latitude of destination", "GPSDestLatitude"],
+ 21 : ["Reference for longitude of destination", "GPSDestLongitudeRef"],
+ 22 : ["Longitude of destination", "GPSDestLongitude"],
+ 23 : ["Reference for bearing of destination", "GPSDestBearingRef"],
+ 24 : ["Bearing of destination", "GPSDestBearing"],
+ 25 : ["Reference for distance to destination", "GPSDestDistanceRef"],
+ 26 : ["Distance to destination", "GPSDestDistance"],
+ 27 : ["Name of GPS processing method", "GPSProcessingMethod"],
+ 28 : ["Name of GPS area", "GPSAreaInformation"],
+ 29 : ["GPS Date", "GPSDateStamp"],
+ 30 : ["GPS differential correction", "GPSDifferential"]
+ };
+
+ this.JpegMeta.JpegFile.prototype._markers = {
+ /* Start Of Frame markers, non-differential, Huffman coding */
+ 0xc0: ["SOF0", "_sofHandler", "Baseline DCT"],
+ 0xc1: ["SOF1", "_sofHandler", "Extended sequential DCT"],
+ 0xc2: ["SOF2", "_sofHandler", "Progressive DCT"],
+ 0xc3: ["SOF3", "_sofHandler", "Lossless (sequential)"],
+
+ /* Start Of Frame markers, differential, Huffman coding */
+ 0xc5: ["SOF5", "_sofHandler", "Differential sequential DCT"],
+ 0xc6: ["SOF6", "_sofHandler", "Differential progressive DCT"],
+ 0xc7: ["SOF7", "_sofHandler", "Differential lossless (sequential)"],
+
+ /* Start Of Frame markers, non-differential, arithmetic coding */
+ 0xc8: ["JPG", null, "Reserved for JPEG extensions"],
+ 0xc9: ["SOF9", "_sofHandler", "Extended sequential DCT"],
+ 0xca: ["SOF10", "_sofHandler", "Progressive DCT"],
+ 0xcb: ["SOF11", "_sofHandler", "Lossless (sequential)"],
+
+ /* Start Of Frame markers, differential, arithmetic coding */
+ 0xcd: ["SOF13", "_sofHandler", "Differential sequential DCT"],
+ 0xce: ["SOF14", "_sofHandler", "Differential progressive DCT"],
+ 0xcf: ["SOF15", "_sofHandler", "Differential lossless (sequential)"],
+
+ /* Huffman table specification */
+ 0xc4: ["DHT", null, "Define Huffman table(s)"],
+ 0xcc: ["DAC", null, "Define arithmetic coding conditioning(s)"],
+
+ /* Restart interval termination" */
+ 0xd0: ["RST0", null, "Restart with modulo 8 count “0”"],
+ 0xd1: ["RST1", null, "Restart with modulo 8 count “1”"],
+ 0xd2: ["RST2", null, "Restart with modulo 8 count “2”"],
+ 0xd3: ["RST3", null, "Restart with modulo 8 count “3”"],
+ 0xd4: ["RST4", null, "Restart with modulo 8 count “4”"],
+ 0xd5: ["RST5", null, "Restart with modulo 8 count “5”"],
+ 0xd6: ["RST6", null, "Restart with modulo 8 count “6”"],
+ 0xd7: ["RST7", null, "Restart with modulo 8 count “7”"],
+
+ /* Other markers */
+ 0xd8: ["SOI", null, "Start of image"],
+ 0xd9: ["EOI", null, "End of image"],
+ 0xda: ["SOS", null, "Start of scan"],
+ 0xdb: ["DQT", null, "Define quantization table(s)"],
+ 0xdc: ["DNL", null, "Define number of lines"],
+ 0xdd: ["DRI", null, "Define restart interval"],
+ 0xde: ["DHP", null, "Define hierarchical progression"],
+ 0xdf: ["EXP", null, "Expand reference component(s)"],
+ 0xe0: ["APP0", "_app0Handler", "Reserved for application segments"],
+ 0xe1: ["APP1", "_app1Handler"],
+ 0xe2: ["APP2", null],
+ 0xe3: ["APP3", null],
+ 0xe4: ["APP4", null],
+ 0xe5: ["APP5", null],
+ 0xe6: ["APP6", null],
+ 0xe7: ["APP7", null],
+ 0xe8: ["APP8", null],
+ 0xe9: ["APP9", null],
+ 0xea: ["APP10", null],
+ 0xeb: ["APP11", null],
+ 0xec: ["APP12", null],
+ 0xed: ["APP13", null],
+ 0xee: ["APP14", null],
+ 0xef: ["APP15", null],
+ 0xf0: ["JPG0", null], /* Reserved for JPEG extensions */
+ 0xf1: ["JPG1", null],
+ 0xf2: ["JPG2", null],
+ 0xf3: ["JPG3", null],
+ 0xf4: ["JPG4", null],
+ 0xf5: ["JPG5", null],
+ 0xf6: ["JPG6", null],
+ 0xf7: ["JPG7", null],
+ 0xf8: ["JPG8", null],
+ 0xf9: ["JPG9", null],
+ 0xfa: ["JPG10", null],
+ 0xfb: ["JPG11", null],
+ 0xfc: ["JPG12", null],
+ 0xfd: ["JPG13", null],
+ 0xfe: ["COM", null], /* Comment */
+
+ /* Reserved markers */
+ 0x01: ["JPG13", null] /* For temporary private use in arithmetic coding */
+ /* 02 -> bf are reserverd */
+ };
+
+ /* Private methods */
+ this.JpegMeta.JpegFile.prototype._addMetaGroup = function _addMetaGroup(name, description) {
+ var group = new JpegMeta.MetaGroup(name, description);
+ this[group.fieldName] = group;
+ this.metaGroups[group.fieldName] = group;
+ return group;
+ };
+
+ this.JpegMeta.JpegFile.prototype._parseIfd = function _parseIfd(endian, _binary_data, base, ifd_offset, tags, name, description) {
+ var num_fields = JpegMeta.parseNum(endian, _binary_data, base + ifd_offset, 2);
+ /* Per tag variables */
+ var i, j;
+ var tag_base;
+ var tag_field;
+ var type, type_field, type_size;
+ var num_values;
+ var value_offset;
+ var value;
+ var _val;
+ var num;
+ var den;
+
+ var group;
+
+ group = this._addMetaGroup(name, description);
+
+ for (var i = 0; i < num_fields; i++) {
+ /* parse the field */
+ tag_base = base + ifd_offset + 2 + (i * 12);
+ tag_field = JpegMeta.parseNum(endian, _binary_data, tag_base, 2);
+ type_field = JpegMeta.parseNum(endian, _binary_data, tag_base + 2, 2);
+ num_values = JpegMeta.parseNum(endian, _binary_data, tag_base + 4, 4);
+ value_offset = JpegMeta.parseNum(endian, _binary_data, tag_base + 8, 4);
+ if (this._types[type_field] === undefined) {
+ continue;
+ }
+ type = this._types[type_field][0];
+ type_size = this._types[type_field][1];
+
+ if (type_size * num_values <= 4) {
+ /* Data is in-line */
+ value_offset = tag_base + 8;
+ } else {
+ value_offset = base + value_offset;
+ }
+
+ /* Read the value */
+ if (type == "UNDEFINED") {
+ value = _binary_data.slice(value_offset, value_offset + num_values);
+ } else if (type == "ASCII") {
+ value = _binary_data.slice(value_offset, value_offset + num_values);
+ value = value.split('\x00')[0];
+ /* strip trail nul */
+ } else {
+ value = new Array();
+ for (j = 0; j < num_values; j++, value_offset += type_size) {
+ if (type == "BYTE" || type == "SHORT" || type == "LONG") {
+ value.push(JpegMeta.parseNum(endian, _binary_data, value_offset, type_size));
+ }
+ if (type == "SBYTE" || type == "SSHORT" || type == "SLONG") {
+ value.push(JpegMeta.parseSnum(endian, _binary_data, value_offset, type_size));
+ }
+ if (type == "RATIONAL") {
+ num = JpegMeta.parseNum(endian, _binary_data, value_offset, 4);
+ den = JpegMeta.parseNum(endian, _binary_data, value_offset + 4, 4);
+ value.push(new JpegMeta.Rational(num, den));
+ }
+ if (type == "SRATIONAL") {
+ num = JpegMeta.parseSnum(endian, _binary_data, value_offset, 4);
+ den = JpegMeta.parseSnum(endian, _binary_data, value_offset + 4, 4);
+ value.push(new JpegMeta.Rational(num, den));
+ }
+ value.push();
+ }
+ if (num_values === 1) {
+ value = value[0];
+ }
+ }
+ if (tags[tag_field] !== undefined) {
+ group._addProperty(tags[tag_field][1], tags[tag_field][0], value);
+ }
+ }
+ };
+
+ this.JpegMeta.JpegFile.prototype._jfifHandler = function _jfifHandler(mark, pos) {
+ if (this.jfif !== undefined) {
+ throw Error("Multiple JFIF segments found");
+ }
+ this._addMetaGroup("jfif", "JFIF");
+ this.jfif._addProperty("version_major", "Version Major", this._binary_data.charCodeAt(pos + 5));
+ this.jfif._addProperty("version_minor", "Version Minor", this._binary_data.charCodeAt(pos + 6));
+ this.jfif._addProperty("version", "JFIF Version", this.jfif.version_major.value + "." + this.jfif.version_minor.value);
+ this.jfif._addProperty("units", "Density Unit", this._binary_data.charCodeAt(pos + 7));
+ this.jfif._addProperty("Xdensity", "X density", JpegMeta.parseNum(">", this._binary_data, pos + 8, 2));
+ this.jfif._addProperty("Ydensity", "Y Density", JpegMeta.parseNum(">", this._binary_data, pos + 10, 2));
+ this.jfif._addProperty("Xthumbnail", "X Thumbnail", JpegMeta.parseNum(">", this._binary_data, pos + 12, 1));
+ this.jfif._addProperty("Ythumbnail", "Y Thumbnail", JpegMeta.parseNum(">", this._binary_data, pos + 13, 1));
+ };
+
+ /* Handle app0 segments */
+ this.JpegMeta.JpegFile.prototype._app0Handler = function app0Handler(mark, pos) {
+ var ident = this._binary_data.slice(pos, pos + 5);
+ if (ident == this._JFIF_IDENT) {
+ this._jfifHandler(mark, pos);
+ } else if (ident == this._JFXX_IDENT) {
+ /* Don't handle JFXX Ident yet */
+ } else {
+ /* Don't know about other idents */
+ }
+ };
+
+ /* Handle app1 segments */
+ this.JpegMeta.JpegFile.prototype._app1Handler = function _app1Handler(mark, pos) {
+ var ident = this._binary_data.slice(pos, pos + 5);
+ if (ident == this._EXIF_IDENT) {
+ this._exifHandler(mark, pos + 6);
+ } else {
+ /* Don't know about other idents */
+ }
+ };
+
+ /* Handle exif segments */
+ JpegMeta.JpegFile.prototype._exifHandler = function _exifHandler(mark, pos) {
+ if (this.exif !== undefined) {
+ throw new Error("Multiple JFIF segments found");
+ }
+
+ /* Parse this TIFF header */
+ var endian;
+ var magic_field;
+ var ifd_offset;
+ var primary_ifd, exif_ifd, gps_ifd;
+ var endian_field = this._binary_data.slice(pos, pos + 2);
+
+ /* Trivia: This 'I' is for Intel, the 'M' is for Motorola */
+ if (endian_field === "II") {
+ endian = "<";
+ } else if (endian_field === "MM") {
+ endian = ">";
+ } else {
+ throw new Error("Malformed TIFF meta-data. Unknown endianess: " + endian_field);
+ }
+
+ magic_field = JpegMeta.parseNum(endian, this._binary_data, pos + 2, 2);
+
+ if (magic_field !== 42) {
+ throw new Error("Malformed TIFF meta-data. Bad magic: " + magic_field);
+ }
+
+ ifd_offset = JpegMeta.parseNum(endian, this._binary_data, pos + 4, 4);
+
+ /* Parse 0th IFD */
+ this._parseIfd(endian, this._binary_data, pos, ifd_offset, this._tifftags, "tiff", "TIFF");
+
+ if (this.tiff.ExifIfdPointer) {
+ this._parseIfd(endian, this._binary_data, pos, this.tiff.ExifIfdPointer.value, this._exiftags, "exif", "Exif");
+ }
+
+ if (this.tiff.GPSInfoIfdPointer) {
+ this._parseIfd(endian, this._binary_data, pos, this.tiff.GPSInfoIfdPointer.value, this._gpstags, "gps", "GPS");
+ if (this.gps.GPSLatitude) {
+ var latitude;
+ latitude = this.gps.GPSLatitude.value[0].asFloat() +
+ (1 / 60) * this.gps.GPSLatitude.value[1].asFloat() +
+ (1 / 3600) * this.gps.GPSLatitude.value[2].asFloat();
+ if (this.gps.GPSLatitudeRef.value === "S") {
+ latitude = -latitude;
+ }
+ this.gps._addProperty("latitude", "Dec. Latitude", latitude);
+ }
+ if (this.gps.GPSLongitude) {
+ var longitude;
+ longitude = this.gps.GPSLongitude.value[0].asFloat() +
+ (1 / 60) * this.gps.GPSLongitude.value[1].asFloat() +
+ (1 / 3600) * this.gps.GPSLongitude.value[2].asFloat();
+ if (this.gps.GPSLongitudeRef.value === "W") {
+ longitude = -longitude;
+ }
+ this.gps._addProperty("longitude", "Dec. Longitude", longitude);
+ }
+ }
+ };
+
+}() );
--- /dev/null
+// Expose via module.exports
+module.exports = window.pluralRuleParser;
+
+// Back-compat: Also expose via mw.lib
+mediaWiki.libs.pluralRuleParser = window.pluralRuleParser;
+++ /dev/null
-/* This is CLDRPluralRuleParser v1.1.3, ported to MediaWiki ResourceLoader */
-
-/**
-* CLDRPluralRuleParser.js
-* A parser engine for CLDR plural rules.
-*
-* Copyright 2012-2014 Santhosh Thottingal and other contributors
-* Released under the MIT license
-* http://opensource.org/licenses/MIT
-*
-* @source https://github.com/santhoshtr/CLDRPluralRuleParser
-* @author Santhosh Thottingal <santhosh.thottingal@gmail.com>
-* @author Timo Tijhof
-* @author Amir Aharoni
-*/
-
-( function ( mw ) {
-/**
- * Evaluates a plural rule in CLDR syntax for a number
- * @param {string} rule
- * @param {integer} number
- * @return {boolean} true if evaluation passed, false if evaluation failed.
- */
-
-function pluralRuleParser(rule, number) {
- 'use strict';
-
- /*
- Syntax: see http://unicode.org/reports/tr35/#Language_Plural_Rules
- -----------------------------------------------------------------
- condition = and_condition ('or' and_condition)*
- ('@integer' samples)?
- ('@decimal' samples)?
- and_condition = relation ('and' relation)*
- relation = is_relation | in_relation | within_relation
- is_relation = expr 'is' ('not')? value
- in_relation = expr (('not')? 'in' | '=' | '!=') range_list
- within_relation = expr ('not')? 'within' range_list
- expr = operand (('mod' | '%') value)?
- operand = 'n' | 'i' | 'f' | 't' | 'v' | 'w'
- range_list = (range | value) (',' range_list)*
- value = digit+
- digit = 0|1|2|3|4|5|6|7|8|9
- range = value'..'value
- samples = sampleRange (',' sampleRange)* (',' ('…'|'...'))?
- sampleRange = decimalValue '~' decimalValue
- decimalValue = value ('.' value)?
- */
-
- // We don't evaluate the samples section of the rule. Ignore it.
- rule = rule.split('@')[0].replace(/^\s*/, '').replace(/\s*$/, '');
-
- if (!rule.length) {
- // Empty rule or 'other' rule.
- return true;
- }
-
- // Indicates the current position in the rule as we parse through it.
- // Shared among all parsing functions below.
- var pos = 0,
- operand,
- expression,
- relation,
- result,
- whitespace = makeRegexParser(/^\s+/),
- value = makeRegexParser(/^\d+/),
- _n_ = makeStringParser('n'),
- _i_ = makeStringParser('i'),
- _f_ = makeStringParser('f'),
- _t_ = makeStringParser('t'),
- _v_ = makeStringParser('v'),
- _w_ = makeStringParser('w'),
- _is_ = makeStringParser('is'),
- _isnot_ = makeStringParser('is not'),
- _isnot_sign_ = makeStringParser('!='),
- _equal_ = makeStringParser('='),
- _mod_ = makeStringParser('mod'),
- _percent_ = makeStringParser('%'),
- _not_ = makeStringParser('not'),
- _in_ = makeStringParser('in'),
- _within_ = makeStringParser('within'),
- _range_ = makeStringParser('..'),
- _comma_ = makeStringParser(','),
- _or_ = makeStringParser('or'),
- _and_ = makeStringParser('and');
-
- function debug() {
- // console.log.apply(console, arguments);
- }
-
- debug('pluralRuleParser', rule, number);
-
- // Try parsers until one works, if none work return null
- function choice(parserSyntax) {
- return function() {
- var i, result;
-
- for (i = 0; i < parserSyntax.length; i++) {
- result = parserSyntax[i]();
-
- if (result !== null) {
- return result;
- }
- }
-
- return null;
- };
- }
-
- // Try several parserSyntax-es in a row.
- // All must succeed; otherwise, return null.
- // This is the only eager one.
- function sequence(parserSyntax) {
- var i, parserRes,
- originalPos = pos,
- result = [];
-
- for (i = 0; i < parserSyntax.length; i++) {
- parserRes = parserSyntax[i]();
-
- if (parserRes === null) {
- pos = originalPos;
-
- return null;
- }
-
- result.push(parserRes);
- }
-
- return result;
- }
-
- // Run the same parser over and over until it fails.
- // Must succeed a minimum of n times; otherwise, return null.
- function nOrMore(n, p) {
- return function() {
- var originalPos = pos,
- result = [],
- parsed = p();
-
- while (parsed !== null) {
- result.push(parsed);
- parsed = p();
- }
-
- if (result.length < n) {
- pos = originalPos;
-
- return null;
- }
-
- return result;
- };
- }
-
- // Helpers - just make parserSyntax out of simpler JS builtin types
- function makeStringParser(s) {
- var len = s.length;
-
- return function() {
- var result = null;
-
- if (rule.substr(pos, len) === s) {
- result = s;
- pos += len;
- }
-
- return result;
- };
- }
-
- function makeRegexParser(regex) {
- return function() {
- var matches = rule.substr(pos).match(regex);
-
- if (matches === null) {
- return null;
- }
-
- pos += matches[0].length;
-
- return matches[0];
- };
- }
-
- /**
- * Integer digits of n.
- */
- function i() {
- var result = _i_();
-
- if (result === null) {
- debug(' -- failed i', parseInt(number, 10));
-
- return result;
- }
-
- result = parseInt(number, 10);
- debug(' -- passed i ', result);
-
- return result;
- }
-
- /**
- * Absolute value of the source number (integer and decimals).
- */
- function n() {
- var result = _n_();
-
- if (result === null) {
- debug(' -- failed n ', number);
-
- return result;
- }
-
- result = parseFloat(number, 10);
- debug(' -- passed n ', result);
-
- return result;
- }
-
- /**
- * Visible fractional digits in n, with trailing zeros.
- */
- function f() {
- var result = _f_();
-
- if (result === null) {
- debug(' -- failed f ', number);
-
- return result;
- }
-
- result = (number + '.').split('.')[1] || 0;
- debug(' -- passed f ', result);
-
- return result;
- }
-
- /**
- * Visible fractional digits in n, without trailing zeros.
- */
- function t() {
- var result = _t_();
-
- if (result === null) {
- debug(' -- failed t ', number);
-
- return result;
- }
-
- result = (number + '.').split('.')[1].replace(/0$/, '') || 0;
- debug(' -- passed t ', result);
-
- return result;
- }
-
- /**
- * Number of visible fraction digits in n, with trailing zeros.
- */
- function v() {
- var result = _v_();
-
- if (result === null) {
- debug(' -- failed v ', number);
-
- return result;
- }
-
- result = (number + '.').split('.')[1].length || 0;
- debug(' -- passed v ', result);
-
- return result;
- }
-
- /**
- * Number of visible fraction digits in n, without trailing zeros.
- */
- function w() {
- var result = _w_();
-
- if (result === null) {
- debug(' -- failed w ', number);
-
- return result;
- }
-
- result = (number + '.').split('.')[1].replace(/0$/, '').length || 0;
- debug(' -- passed w ', result);
-
- return result;
- }
-
- // operand = 'n' | 'i' | 'f' | 't' | 'v' | 'w'
- operand = choice([n, i, f, t, v, w]);
-
- // expr = operand (('mod' | '%') value)?
- expression = choice([mod, operand]);
-
- function mod() {
- var result = sequence(
- [operand, whitespace, choice([_mod_, _percent_]), whitespace, value]
- );
-
- if (result === null) {
- debug(' -- failed mod');
-
- return null;
- }
-
- debug(' -- passed ' + parseInt(result[0], 10) + ' ' + result[2] + ' ' + parseInt(result[4], 10));
-
- return parseInt(result[0], 10) % parseInt(result[4], 10);
- }
-
- function not() {
- var result = sequence([whitespace, _not_]);
-
- if (result === null) {
- debug(' -- failed not');
-
- return null;
- }
-
- return result[1];
- }
-
- // is_relation = expr 'is' ('not')? value
- function is() {
- var result = sequence([expression, whitespace, choice([_is_]), whitespace, value]);
-
- if (result !== null) {
- debug(' -- passed is : ' + result[0] + ' == ' + parseInt(result[4], 10));
-
- return result[0] === parseInt(result[4], 10);
- }
-
- debug(' -- failed is');
-
- return null;
- }
-
- // is_relation = expr 'is' ('not')? value
- function isnot() {
- var result = sequence(
- [expression, whitespace, choice([_isnot_, _isnot_sign_]), whitespace, value]
- );
-
- if (result !== null) {
- debug(' -- passed isnot: ' + result[0] + ' != ' + parseInt(result[4], 10));
-
- return result[0] !== parseInt(result[4], 10);
- }
-
- debug(' -- failed isnot');
-
- return null;
- }
-
- function not_in() {
- var i, range_list,
- result = sequence([expression, whitespace, _isnot_sign_, whitespace, rangeList]);
-
- if (result !== null) {
- debug(' -- passed not_in: ' + result[0] + ' != ' + result[4]);
- range_list = result[4];
-
- for (i = 0; i < range_list.length; i++) {
- if (parseInt(range_list[i], 10) === parseInt(result[0], 10)) {
- return false;
- }
- }
-
- return true;
- }
-
- debug(' -- failed not_in');
-
- return null;
- }
-
- // range_list = (range | value) (',' range_list)*
- function rangeList() {
- var result = sequence([choice([range, value]), nOrMore(0, rangeTail)]),
- resultList = [];
-
- if (result !== null) {
- resultList = resultList.concat(result[0]);
-
- if (result[1][0]) {
- resultList = resultList.concat(result[1][0]);
- }
-
- return resultList;
- }
-
- debug(' -- failed rangeList');
-
- return null;
- }
-
- function rangeTail() {
- // ',' range_list
- var result = sequence([_comma_, rangeList]);
-
- if (result !== null) {
- return result[1];
- }
-
- debug(' -- failed rangeTail');
-
- return null;
- }
-
- // range = value'..'value
- function range() {
- var i, array, left, right,
- result = sequence([value, _range_, value]);
-
- if (result !== null) {
- debug(' -- passed range');
-
- array = [];
- left = parseInt(result[0], 10);
- right = parseInt(result[2], 10);
-
- for (i = left; i <= right; i++) {
- array.push(i);
- }
-
- return array;
- }
-
- debug(' -- failed range');
-
- return null;
- }
-
- function _in() {
- var result, range_list, i;
-
- // in_relation = expr ('not')? 'in' range_list
- result = sequence(
- [expression, nOrMore(0, not), whitespace, choice([_in_, _equal_]), whitespace, rangeList]
- );
-
- if (result !== null) {
- debug(' -- passed _in:' + result);
-
- range_list = result[5];
-
- for (i = 0; i < range_list.length; i++) {
- if (parseInt(range_list[i], 10) === parseInt(result[0], 10)) {
- return (result[1][0] !== 'not');
- }
- }
-
- return (result[1][0] === 'not');
- }
-
- debug(' -- failed _in ');
-
- return null;
- }
-
- /**
- * The difference between "in" and "within" is that
- * "in" only includes integers in the specified range,
- * while "within" includes all values.
- */
- function within() {
- var range_list, result;
-
- // within_relation = expr ('not')? 'within' range_list
- result = sequence(
- [expression, nOrMore(0, not), whitespace, _within_, whitespace, rangeList]
- );
-
- if (result !== null) {
- debug(' -- passed within');
-
- range_list = result[5];
-
- if ((result[0] >= parseInt(range_list[0], 10)) &&
- (result[0] < parseInt(range_list[range_list.length - 1], 10))) {
-
- return (result[1][0] !== 'not');
- }
-
- return (result[1][0] === 'not');
- }
-
- debug(' -- failed within ');
-
- return null;
- }
-
- // relation = is_relation | in_relation | within_relation
- relation = choice([is, not_in, isnot, _in, within]);
-
- // and_condition = relation ('and' relation)*
- function and() {
- var i,
- result = sequence([relation, nOrMore(0, andTail)]);
-
- if (result) {
- if (!result[0]) {
- return false;
- }
-
- for (i = 0; i < result[1].length; i++) {
- if (!result[1][i]) {
- return false;
- }
- }
-
- return true;
- }
-
- debug(' -- failed and');
-
- return null;
- }
-
- // ('and' relation)*
- function andTail() {
- var result = sequence([whitespace, _and_, whitespace, relation]);
-
- if (result !== null) {
- debug(' -- passed andTail' + result);
-
- return result[3];
- }
-
- debug(' -- failed andTail');
-
- return null;
-
- }
- // ('or' and_condition)*
- function orTail() {
- var result = sequence([whitespace, _or_, whitespace, and]);
-
- if (result !== null) {
- debug(' -- passed orTail: ' + result[3]);
-
- return result[3];
- }
-
- debug(' -- failed orTail');
-
- return null;
- }
-
- // condition = and_condition ('or' and_condition)*
- function condition() {
- var i,
- result = sequence([and, nOrMore(0, orTail)]);
-
- if (result) {
- for (i = 0; i < result[1].length; i++) {
- if (result[1][i]) {
- return true;
- }
- }
-
- return result[0];
- }
-
- return false;
- }
-
- result = condition();
-
- /**
- * For success, the pos must have gotten to the end of the rule
- * and returned a non-null.
- * n.b. This is part of language infrastructure,
- * so we do not throw an internationalizable message.
- */
- if (result === null) {
- throw new Error('Parse error at position ' + pos.toString() + ' for rule: ' + rule);
- }
-
- if (pos !== rule.length) {
- debug('Warning: Rule not parsed completely. Parser stopped at ' + rule.substr(0, pos) + ' for rule: ' + rule);
- }
-
- return result;
-}
-
-/* pluralRuleParser ends here */
-mw.libs.pluralRuleParser = pluralRuleParser;
-module.exports = pluralRuleParser;
-
-} )( mediaWiki );
+++ /dev/null
-/**
- * This is JsJpegMeta v1.0
- * From: https://code.google.com/p/jsjpegmeta/downloads/list
- * From: https://github.com/bennoleslie/jsjpegmeta/blob/v1.0.0/jpegmeta.js
- *
- * Ported to MediaWiki ResourceLoader by Bryan Tong Minh
- * Changes:
- * - Add closure.
- * - Add this.JpegMeta assignment to expose it as global.
- * - Add export as module.
- * - Add mw.libs.jpegmeta wrapper.
- */
-
-( function ( mw ) {
- /*
- Copyright (c) 2009 Ben Leslie
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- */
-
- /*
- This JavaScript library is used to parse meta-data from files
- with mime-type image/jpeg.
-
- Include it with something like:
-
- <script type="text/javascript" src="jpegmeta.js"></script>
-
- This adds a single 'module' object called 'JpegMeta' to the global
- namespace.
-
- Public Functions
- ----------------
- JpegMeta.parseNum - parse unsigned integers from binary data
- JpegMeta.parseSnum - parse signed integers from binary data
-
- Public Classes
- --------------
- JpegMeta.Rational - A rational number class
- JpegMeta.JfifSegment
- JpegMeta.ExifSegment
- JpegMeta.JpegFile - Primary class for Javascript parsing
- */
-
- var JpegMeta = {};
- // MediaWiki: Expose as global
- this.JpegMeta = JpegMeta;
-
- /*
- parse an unsigned number of size bytes at offset in some binary string data.
- If endian
- is "<" parse the data as little endian, if endian
- is ">" parse as big-endian.
- */
- JpegMeta.parseNum = function parseNum(endian, data, offset, size) {
- var i;
- var ret;
- var big_endian = (endian === ">");
- if (offset === undefined) offset = 0;
- if (size === undefined) size = data.length - offset;
- for (big_endian ? i = offset : i = offset + size - 1;
- big_endian ? i < offset + size : i >= offset;
- big_endian ? i++ : i--) {
- ret <<= 8;
- ret += data.charCodeAt(i);
- }
- return ret;
- };
-
- /*
- parse an signed number of size bytes at offset in some binary string data.
- If endian
- is "<" parse the data as little endian, if endian
- is ">" parse as big-endian.
- */
- JpegMeta.parseSnum = function parseSnum(endian, data, offset, size) {
- var i;
- var ret;
- var neg;
- var big_endian = (endian === ">");
- if (offset === undefined) offset = 0;
- if (size === undefined) size = data.length - offset;
- for (big_endian ? i = offset : i = offset + size - 1;
- big_endian ? i < offset + size : i >= offset;
- big_endian ? i++ : i--) {
- if (neg === undefined) {
- /* Negative if top bit is set */
- neg = (data.charCodeAt(i) & 0x80) === 0x80;
- }
- ret <<= 8;
- /* If it is negative we invert the bits */
- ret += neg ? ~data.charCodeAt(i) & 0xff: data.charCodeAt(i);
- }
- if (neg) {
- /* If it is negative we do two's complement */
- ret += 1;
- ret *= -1;
- }
- return ret;
- };
-
- /* Rational number class */
- JpegMeta.Rational = function Rational(num, den)
- {
- this.num = num;
- this.den = den || 1;
- return this;
- };
-
- /* Rational number methods */
- JpegMeta.Rational.prototype.toString = function toString() {
- if (this.num === 0) {
- return "" + this.num;
- }
- if (this.den === 1) {
- return "" + this.num;
- }
- if (this.num === 1) {
- return this.num + " / " + this.den;
- }
- return this.num / this.den; // + "/" + this.den;
- };
-
- JpegMeta.Rational.prototype.asFloat = function asFloat() {
- return this.num / this.den;
- };
-
- /* MetaGroup class */
- JpegMeta.MetaGroup = function MetaGroup(fieldName, description) {
- this.fieldName = fieldName;
- this.description = description;
- this.metaProps = {};
- return this;
- };
-
- JpegMeta.MetaGroup.prototype._addProperty = function _addProperty(fieldName, description, value) {
- var property = new JpegMeta.MetaProp(fieldName, description, value);
- this[property.fieldName] = property;
- this.metaProps[property.fieldName] = property;
- };
-
- JpegMeta.MetaGroup.prototype.toString = function toString() {
- return "[MetaGroup " + this.description + "]";
- };
-
- /* MetaProp class */
- JpegMeta.MetaProp = function MetaProp(fieldName, description, value) {
- this.fieldName = fieldName;
- this.description = description;
- this.value = value;
- return this;
- };
-
- JpegMeta.MetaProp.prototype.toString = function toString() {
- return "" + this.value;
- };
-
- /* JpegFile class */
- JpegMeta.JpegFile = function JpegFile(binary_data, filename) {
- /* Change this to EOI if we want to parse. */
- var break_segment = this._SOS;
-
- this.metaGroups = {};
- this._binary_data = binary_data;
- this.filename = filename;
-
- /* Go through and parse. */
- var pos = 0;
- var pos_start_of_segment = 0;
- var delim;
- var mark;
- var _mark;
- var segsize;
- var headersize;
- var mark_code;
- var mark_fn;
-
- /* Check to see if this looks like a JPEG file */
- if (this._binary_data.slice(0, 2) !== this._SOI_MARKER) {
- throw new Error("Doesn't look like a JPEG file. First two bytes are " +
- this._binary_data.charCodeAt(0) + "," +
- this._binary_data.charCodeAt(1) + ".");
- }
-
- pos += 2;
-
- while (pos < this._binary_data.length) {
- delim = this._binary_data.charCodeAt(pos++);
- mark = this._binary_data.charCodeAt(pos++);
-
- pos_start_of_segment = pos;
-
- if (delim != this._DELIM) {
- break;
- }
-
- if (mark === break_segment) {
- break;
- }
-
- headersize = JpegMeta.parseNum(">", this._binary_data, pos, 2);
-
- /* Find the end */
- pos += headersize;
- while (pos < this._binary_data.length) {
- delim = this._binary_data.charCodeAt(pos++);
- if (delim == this._DELIM) {
- _mark = this._binary_data.charCodeAt(pos++);
- if (_mark != 0x0) {
- pos -= 2;
- break;
- }
- }
- }
-
- segsize = pos - pos_start_of_segment;
-
- if (this._markers[mark]) {
- mark_code = this._markers[mark][0];
- mark_fn = this._markers[mark][1];
- } else {
- mark_code = "UNKN";
- mark_fn = undefined;
- }
-
- if (mark_fn) {
- this[mark_fn](mark, pos_start_of_segment + 2);
- }
-
- }
-
- if (this.general === undefined) {
- throw Error("Invalid JPEG file.");
- }
-
- return this;
- };
-
- this.JpegMeta.JpegFile.prototype.toString = function () {
- return "[JpegFile " + this.filename + " " +
- this.general.type + " " +
- this.general.pixelWidth + "x" +
- this.general.pixelHeight +
- " Depth: " + this.general.depth + "]";
- };
-
- /* Some useful constants */
- this.JpegMeta.JpegFile.prototype._SOI_MARKER = '\xff\xd8';
- this.JpegMeta.JpegFile.prototype._DELIM = 0xff;
- this.JpegMeta.JpegFile.prototype._EOI = 0xd9;
- this.JpegMeta.JpegFile.prototype._SOS = 0xda;
-
- this.JpegMeta.JpegFile.prototype._sofHandler = function _sofHandler (mark, pos) {
- if (this.general !== undefined) {
- throw Error("Unexpected multiple-frame image");
- }
-
- this._addMetaGroup("general", "General");
- this.general._addProperty("depth", "Depth", JpegMeta.parseNum(">", this._binary_data, pos, 1));
- this.general._addProperty("pixelHeight", "Pixel Height", JpegMeta.parseNum(">", this._binary_data, pos + 1, 2));
- this.general._addProperty("pixelWidth", "Pixel Width",JpegMeta.parseNum(">", this._binary_data, pos + 3, 2));
- this.general._addProperty("type", "Type", this._markers[mark][2]);
- };
-
- /* JFIF idents */
- this.JpegMeta.JpegFile.prototype._JFIF_IDENT = "JFIF\x00";
- this.JpegMeta.JpegFile.prototype._JFXX_IDENT = "JFXX\x00";
-
- /* Exif idents */
- this.JpegMeta.JpegFile.prototype._EXIF_IDENT = "Exif\x00";
-
- /* TIFF types */
- this.JpegMeta.JpegFile.prototype._types = {
- /* The format is identifier : ["type name", type_size_in_bytes ] */
- 1 : ["BYTE", 1],
- 2 : ["ASCII", 1],
- 3 : ["SHORT", 2],
- 4 : ["LONG", 4],
- 5 : ["RATIONAL", 8],
- 6 : ["SBYTE", 1],
- 7 : ["UNDEFINED", 1],
- 8 : ["SSHORT", 2],
- 9 : ["SLONG", 4],
- 10 : ["SRATIONAL", 8],
- 11 : ["FLOAT", 4],
- 12 : ["DOUBLE", 8]
- };
-
- this.JpegMeta.JpegFile.prototype._tifftags = {
- /* A. Tags relating to image data structure */
- 256 : ["Image width", "ImageWidth"],
- 257 : ["Image height", "ImageLength"],
- 258 : ["Number of bits per component", "BitsPerSample"],
- 259 : ["Compression scheme", "Compression",
- {1 : "uncompressed", 6 : "JPEG compression" }],
- 262 : ["Pixel composition", "PhotmetricInerpretation",
- {2 : "RGB", 6 : "YCbCr"}],
- 274 : ["Orientation of image", "Orientation",
- /* FIXME: Check the mirror-image / reverse encoding and rotation */
- {1 : "Normal", 2 : "Reverse?",
- 3 : "Upside-down", 4 : "Upside-down Reverse",
- 5 : "90 degree CW", 6 : "90 degree CW reverse",
- 7 : "90 degree CCW", 8 : "90 degree CCW reverse"}],
- 277 : ["Number of components", "SamplesPerPixel"],
- 284 : ["Image data arrangement", "PlanarConfiguration",
- {1 : "chunky format", 2 : "planar format"}],
- 530 : ["Subsampling ratio of Y to C", "YCbCrSubSampling"],
- 531 : ["Y and C positioning", "YCbCrPositioning",
- {1 : "centered", 2 : "co-sited"}],
- 282 : ["X Resolution", "XResolution"],
- 283 : ["Y Resolution", "YResolution"],
- 296 : ["Resolution Unit", "ResolutionUnit",
- {2 : "inches", 3 : "centimeters"}],
- /* B. Tags realting to recording offset */
- 273 : ["Image data location", "StripOffsets"],
- 278 : ["Number of rows per strip", "RowsPerStrip"],
- 279 : ["Bytes per compressed strip", "StripByteCounts"],
- 513 : ["Offset to JPEG SOI", "JPEGInterchangeFormat"],
- 514 : ["Bytes of JPEG Data", "JPEGInterchangeFormatLength"],
- /* C. Tags relating to image data characteristics */
- 301 : ["Transfer function", "TransferFunction"],
- 318 : ["White point chromaticity", "WhitePoint"],
- 319 : ["Chromaticities of primaries", "PrimaryChromaticities"],
- 529 : ["Color space transformation matrix coefficients", "YCbCrCoefficients"],
- 532 : ["Pair of black and white reference values", "ReferenceBlackWhite"],
- /* D. Other tags */
- 306 : ["Date and time", "DateTime"],
- 270 : ["Image title", "ImageDescription"],
- 271 : ["Make", "Make"],
- 272 : ["Model", "Model"],
- 305 : ["Software", "Software"],
- 315 : ["Person who created the image", "Artist"],
- 316 : ["Host Computer", "HostComputer"],
- 33432 : ["Copyright holder", "Copyright"],
-
- 34665 : ["Exif tag", "ExifIfdPointer"],
- 34853 : ["GPS tag", "GPSInfoIfdPointer"]
- };
-
- this.JpegMeta.JpegFile.prototype._exiftags = {
- /* Tag Support Levels (2) - 0th IFX Exif Private Tags */
- /* A. Tags Relating to Version */
- 36864 : ["Exif Version", "ExifVersion"],
- 40960 : ["FlashPix Version", "FlashpixVersion"],
-
- /* B. Tag Relating to Image Data Characteristics */
- 40961 : ["Color Space", "ColorSpace"],
-
- /* C. Tags Relating to Image Configuration */
- 37121 : ["Meaning of each component", "ComponentsConfiguration"],
- 37122 : ["Compressed Bits Per Pixel", "CompressedBitsPerPixel"],
- 40962 : ["Pixel X Dimension", "PixelXDimension"],
- 40963 : ["Pixel Y Dimension", "PixelYDimension"],
-
- /* D. Tags Relating to User Information */
- 37500 : ["Manufacturer notes", "MakerNote"],
- 37510 : ["User comments", "UserComment"],
-
- /* E. Tag Relating to Related File Information */
- 40964 : ["Related audio file", "RelatedSoundFile"],
-
- /* F. Tags Relating to Date and Time */
- 36867 : ["Date Time Original", "DateTimeOriginal"],
- 36868 : ["Date Time Digitized", "DateTimeDigitized"],
- 37520 : ["DateTime subseconds", "SubSecTime"],
- 37521 : ["DateTimeOriginal subseconds", "SubSecTimeOriginal"],
- 37522 : ["DateTimeDigitized subseconds", "SubSecTimeDigitized"],
-
- /* G. Tags Relating to Picture-Taking Conditions */
- 33434 : ["Exposure time", "ExposureTime"],
- 33437 : ["FNumber", "FNumber"],
- 34850 : ["Exposure program", "ExposureProgram"],
- 34852 : ["Spectral sensitivity", "SpectralSensitivity"],
- 34855 : ["ISO Speed Ratings", "ISOSpeedRatings"],
- 34856 : ["Optoelectric coefficient", "OECF"],
- 37377 : ["Shutter Speed", "ShutterSpeedValue"],
- 37378 : ["Aperture Value", "ApertureValue"],
- 37379 : ["Brightness", "BrightnessValue"],
- 37380 : ["Exposure Bias Value", "ExposureBiasValue"],
- 37381 : ["Max Aperture Value", "MaxApertureValue"],
- 37382 : ["Subject Distance", "SubjectDistance"],
- 37383 : ["Metering Mode", "MeteringMode"],
- 37384 : ["Light Source", "LightSource"],
- 37385 : ["Flash", "Flash"],
- 37386 : ["Focal Length", "FocalLength"],
- 37396 : ["Subject Area", "SubjectArea"],
- 41483 : ["Flash Energy", "FlashEnergy"],
- 41484 : ["Spatial Frequency Response", "SpatialFrequencyResponse"],
- 41486 : ["Focal Plane X Resolution", "FocalPlaneXResolution"],
- 41487 : ["Focal Plane Y Resolution", "FocalPlaneYResolution"],
- 41488 : ["Focal Plane Resolution Unit", "FocalPlaneResolutionUnit"],
- 41492 : ["Subject Location", "SubjectLocation"],
- 41493 : ["Exposure Index", "ExposureIndex"],
- 41495 : ["Sensing Method", "SensingMethod"],
- 41728 : ["File Source", "FileSource"],
- 41729 : ["Scene Type", "SceneType"],
- 41730 : ["CFA Pattern", "CFAPattern"],
- 41985 : ["Custom Rendered", "CustomRendered"],
- 41986 : ["Exposure Mode", "Exposure Mode"],
- 41987 : ["White Balance", "WhiteBalance"],
- 41988 : ["Digital Zoom Ratio", "DigitalZoomRatio"],
- 41990 : ["Scene Capture Type", "SceneCaptureType"],
- 41991 : ["Gain Control", "GainControl"],
- 41992 : ["Contrast", "Contrast"],
- 41993 : ["Saturation", "Saturation"],
- 41994 : ["Sharpness", "Sharpness"],
- 41995 : ["Device settings description", "DeviceSettingDescription"],
- 41996 : ["Subject distance range", "SubjectDistanceRange"],
-
- /* H. Other Tags */
- 42016 : ["Unique image ID", "ImageUniqueID"],
-
- 40965 : ["Interoperability tag", "InteroperabilityIFDPointer"]
- };
-
- this.JpegMeta.JpegFile.prototype._gpstags = {
- /* A. Tags Relating to GPS */
- 0 : ["GPS tag version", "GPSVersionID"],
- 1 : ["North or South Latitude", "GPSLatitudeRef"],
- 2 : ["Latitude", "GPSLatitude"],
- 3 : ["East or West Longitude", "GPSLongitudeRef"],
- 4 : ["Longitude", "GPSLongitude"],
- 5 : ["Altitude reference", "GPSAltitudeRef"],
- 6 : ["Altitude", "GPSAltitude"],
- 7 : ["GPS time (atomic clock)", "GPSTimeStamp"],
- 8 : ["GPS satellites usedd for measurement", "GPSSatellites"],
- 9 : ["GPS receiver status", "GPSStatus"],
- 10 : ["GPS mesaurement mode", "GPSMeasureMode"],
- 11 : ["Measurement precision", "GPSDOP"],
- 12 : ["Speed unit", "GPSSpeedRef"],
- 13 : ["Speed of GPS receiver", "GPSSpeed"],
- 14 : ["Reference for direction of movement", "GPSTrackRef"],
- 15 : ["Direction of movement", "GPSTrack"],
- 16 : ["Reference for direction of image", "GPSImgDirectionRef"],
- 17 : ["Direction of image", "GPSImgDirection"],
- 18 : ["Geodetic survey data used", "GPSMapDatum"],
- 19 : ["Reference for latitude of destination", "GPSDestLatitudeRef"],
- 20 : ["Latitude of destination", "GPSDestLatitude"],
- 21 : ["Reference for longitude of destination", "GPSDestLongitudeRef"],
- 22 : ["Longitude of destination", "GPSDestLongitude"],
- 23 : ["Reference for bearing of destination", "GPSDestBearingRef"],
- 24 : ["Bearing of destination", "GPSDestBearing"],
- 25 : ["Reference for distance to destination", "GPSDestDistanceRef"],
- 26 : ["Distance to destination", "GPSDestDistance"],
- 27 : ["Name of GPS processing method", "GPSProcessingMethod"],
- 28 : ["Name of GPS area", "GPSAreaInformation"],
- 29 : ["GPS Date", "GPSDateStamp"],
- 30 : ["GPS differential correction", "GPSDifferential"]
- };
-
- this.JpegMeta.JpegFile.prototype._markers = {
- /* Start Of Frame markers, non-differential, Huffman coding */
- 0xc0: ["SOF0", "_sofHandler", "Baseline DCT"],
- 0xc1: ["SOF1", "_sofHandler", "Extended sequential DCT"],
- 0xc2: ["SOF2", "_sofHandler", "Progressive DCT"],
- 0xc3: ["SOF3", "_sofHandler", "Lossless (sequential)"],
-
- /* Start Of Frame markers, differential, Huffman coding */
- 0xc5: ["SOF5", "_sofHandler", "Differential sequential DCT"],
- 0xc6: ["SOF6", "_sofHandler", "Differential progressive DCT"],
- 0xc7: ["SOF7", "_sofHandler", "Differential lossless (sequential)"],
-
- /* Start Of Frame markers, non-differential, arithmetic coding */
- 0xc8: ["JPG", null, "Reserved for JPEG extensions"],
- 0xc9: ["SOF9", "_sofHandler", "Extended sequential DCT"],
- 0xca: ["SOF10", "_sofHandler", "Progressive DCT"],
- 0xcb: ["SOF11", "_sofHandler", "Lossless (sequential)"],
-
- /* Start Of Frame markers, differential, arithmetic coding */
- 0xcd: ["SOF13", "_sofHandler", "Differential sequential DCT"],
- 0xce: ["SOF14", "_sofHandler", "Differential progressive DCT"],
- 0xcf: ["SOF15", "_sofHandler", "Differential lossless (sequential)"],
-
- /* Huffman table specification */
- 0xc4: ["DHT", null, "Define Huffman table(s)"],
- 0xcc: ["DAC", null, "Define arithmetic coding conditioning(s)"],
-
- /* Restart interval termination" */
- 0xd0: ["RST0", null, "Restart with modulo 8 count “0”"],
- 0xd1: ["RST1", null, "Restart with modulo 8 count “1”"],
- 0xd2: ["RST2", null, "Restart with modulo 8 count “2”"],
- 0xd3: ["RST3", null, "Restart with modulo 8 count “3”"],
- 0xd4: ["RST4", null, "Restart with modulo 8 count “4”"],
- 0xd5: ["RST5", null, "Restart with modulo 8 count “5”"],
- 0xd6: ["RST6", null, "Restart with modulo 8 count “6”"],
- 0xd7: ["RST7", null, "Restart with modulo 8 count “7”"],
-
- /* Other markers */
- 0xd8: ["SOI", null, "Start of image"],
- 0xd9: ["EOI", null, "End of image"],
- 0xda: ["SOS", null, "Start of scan"],
- 0xdb: ["DQT", null, "Define quantization table(s)"],
- 0xdc: ["DNL", null, "Define number of lines"],
- 0xdd: ["DRI", null, "Define restart interval"],
- 0xde: ["DHP", null, "Define hierarchical progression"],
- 0xdf: ["EXP", null, "Expand reference component(s)"],
- 0xe0: ["APP0", "_app0Handler", "Reserved for application segments"],
- 0xe1: ["APP1", "_app1Handler"],
- 0xe2: ["APP2", null],
- 0xe3: ["APP3", null],
- 0xe4: ["APP4", null],
- 0xe5: ["APP5", null],
- 0xe6: ["APP6", null],
- 0xe7: ["APP7", null],
- 0xe8: ["APP8", null],
- 0xe9: ["APP9", null],
- 0xea: ["APP10", null],
- 0xeb: ["APP11", null],
- 0xec: ["APP12", null],
- 0xed: ["APP13", null],
- 0xee: ["APP14", null],
- 0xef: ["APP15", null],
- 0xf0: ["JPG0", null], /* Reserved for JPEG extensions */
- 0xf1: ["JPG1", null],
- 0xf2: ["JPG2", null],
- 0xf3: ["JPG3", null],
- 0xf4: ["JPG4", null],
- 0xf5: ["JPG5", null],
- 0xf6: ["JPG6", null],
- 0xf7: ["JPG7", null],
- 0xf8: ["JPG8", null],
- 0xf9: ["JPG9", null],
- 0xfa: ["JPG10", null],
- 0xfb: ["JPG11", null],
- 0xfc: ["JPG12", null],
- 0xfd: ["JPG13", null],
- 0xfe: ["COM", null], /* Comment */
-
- /* Reserved markers */
- 0x01: ["JPG13", null] /* For temporary private use in arithmetic coding */
- /* 02 -> bf are reserverd */
- };
-
- /* Private methods */
- this.JpegMeta.JpegFile.prototype._addMetaGroup = function _addMetaGroup(name, description) {
- var group = new JpegMeta.MetaGroup(name, description);
- this[group.fieldName] = group;
- this.metaGroups[group.fieldName] = group;
- return group;
- };
-
- this.JpegMeta.JpegFile.prototype._parseIfd = function _parseIfd(endian, _binary_data, base, ifd_offset, tags, name, description) {
- var num_fields = JpegMeta.parseNum(endian, _binary_data, base + ifd_offset, 2);
- /* Per tag variables */
- var i, j;
- var tag_base;
- var tag_field;
- var type, type_field, type_size;
- var num_values;
- var value_offset;
- var value;
- var _val;
- var num;
- var den;
-
- var group;
-
- group = this._addMetaGroup(name, description);
-
- for (var i = 0; i < num_fields; i++) {
- /* parse the field */
- tag_base = base + ifd_offset + 2 + (i * 12);
- tag_field = JpegMeta.parseNum(endian, _binary_data, tag_base, 2);
- type_field = JpegMeta.parseNum(endian, _binary_data, tag_base + 2, 2);
- num_values = JpegMeta.parseNum(endian, _binary_data, tag_base + 4, 4);
- value_offset = JpegMeta.parseNum(endian, _binary_data, tag_base + 8, 4);
- if (this._types[type_field] === undefined) {
- continue;
- }
- type = this._types[type_field][0];
- type_size = this._types[type_field][1];
-
- if (type_size * num_values <= 4) {
- /* Data is in-line */
- value_offset = tag_base + 8;
- } else {
- value_offset = base + value_offset;
- }
-
- /* Read the value */
- if (type == "UNDEFINED") {
- value = _binary_data.slice(value_offset, value_offset + num_values);
- } else if (type == "ASCII") {
- value = _binary_data.slice(value_offset, value_offset + num_values);
- value = value.split('\x00')[0];
- /* strip trail nul */
- } else {
- value = new Array();
- for (j = 0; j < num_values; j++, value_offset += type_size) {
- if (type == "BYTE" || type == "SHORT" || type == "LONG") {
- value.push(JpegMeta.parseNum(endian, _binary_data, value_offset, type_size));
- }
- if (type == "SBYTE" || type == "SSHORT" || type == "SLONG") {
- value.push(JpegMeta.parseSnum(endian, _binary_data, value_offset, type_size));
- }
- if (type == "RATIONAL") {
- num = JpegMeta.parseNum(endian, _binary_data, value_offset, 4);
- den = JpegMeta.parseNum(endian, _binary_data, value_offset + 4, 4);
- value.push(new JpegMeta.Rational(num, den));
- }
- if (type == "SRATIONAL") {
- num = JpegMeta.parseSnum(endian, _binary_data, value_offset, 4);
- den = JpegMeta.parseSnum(endian, _binary_data, value_offset + 4, 4);
- value.push(new JpegMeta.Rational(num, den));
- }
- value.push();
- }
- if (num_values === 1) {
- value = value[0];
- }
- }
- if (tags[tag_field] !== undefined) {
- group._addProperty(tags[tag_field][1], tags[tag_field][0], value);
- }
- }
- };
-
- this.JpegMeta.JpegFile.prototype._jfifHandler = function _jfifHandler(mark, pos) {
- if (this.jfif !== undefined) {
- throw Error("Multiple JFIF segments found");
- }
- this._addMetaGroup("jfif", "JFIF");
- this.jfif._addProperty("version_major", "Version Major", this._binary_data.charCodeAt(pos + 5));
- this.jfif._addProperty("version_minor", "Version Minor", this._binary_data.charCodeAt(pos + 6));
- this.jfif._addProperty("version", "JFIF Version", this.jfif.version_major.value + "." + this.jfif.version_minor.value);
- this.jfif._addProperty("units", "Density Unit", this._binary_data.charCodeAt(pos + 7));
- this.jfif._addProperty("Xdensity", "X density", JpegMeta.parseNum(">", this._binary_data, pos + 8, 2));
- this.jfif._addProperty("Ydensity", "Y Density", JpegMeta.parseNum(">", this._binary_data, pos + 10, 2));
- this.jfif._addProperty("Xthumbnail", "X Thumbnail", JpegMeta.parseNum(">", this._binary_data, pos + 12, 1));
- this.jfif._addProperty("Ythumbnail", "Y Thumbnail", JpegMeta.parseNum(">", this._binary_data, pos + 13, 1));
- };
-
- /* Handle app0 segments */
- this.JpegMeta.JpegFile.prototype._app0Handler = function app0Handler(mark, pos) {
- var ident = this._binary_data.slice(pos, pos + 5);
- if (ident == this._JFIF_IDENT) {
- this._jfifHandler(mark, pos);
- } else if (ident == this._JFXX_IDENT) {
- /* Don't handle JFXX Ident yet */
- } else {
- /* Don't know about other idents */
- }
- };
-
- /* Handle app1 segments */
- this.JpegMeta.JpegFile.prototype._app1Handler = function _app1Handler(mark, pos) {
- var ident = this._binary_data.slice(pos, pos + 5);
- if (ident == this._EXIF_IDENT) {
- this._exifHandler(mark, pos + 6);
- } else {
- /* Don't know about other idents */
- }
- };
-
- /* Handle exif segments */
- JpegMeta.JpegFile.prototype._exifHandler = function _exifHandler(mark, pos) {
- if (this.exif !== undefined) {
- throw new Error("Multiple JFIF segments found");
- }
-
- /* Parse this TIFF header */
- var endian;
- var magic_field;
- var ifd_offset;
- var primary_ifd, exif_ifd, gps_ifd;
- var endian_field = this._binary_data.slice(pos, pos + 2);
-
- /* Trivia: This 'I' is for Intel, the 'M' is for Motorola */
- if (endian_field === "II") {
- endian = "<";
- } else if (endian_field === "MM") {
- endian = ">";
- } else {
- throw new Error("Malformed TIFF meta-data. Unknown endianess: " + endian_field);
- }
-
- magic_field = JpegMeta.parseNum(endian, this._binary_data, pos + 2, 2);
-
- if (magic_field !== 42) {
- throw new Error("Malformed TIFF meta-data. Bad magic: " + magic_field);
- }
-
- ifd_offset = JpegMeta.parseNum(endian, this._binary_data, pos + 4, 4);
-
- /* Parse 0th IFD */
- this._parseIfd(endian, this._binary_data, pos, ifd_offset, this._tifftags, "tiff", "TIFF");
-
- if (this.tiff.ExifIfdPointer) {
- this._parseIfd(endian, this._binary_data, pos, this.tiff.ExifIfdPointer.value, this._exiftags, "exif", "Exif");
- }
-
- if (this.tiff.GPSInfoIfdPointer) {
- this._parseIfd(endian, this._binary_data, pos, this.tiff.GPSInfoIfdPointer.value, this._gpstags, "gps", "GPS");
- if (this.gps.GPSLatitude) {
- var latitude;
- latitude = this.gps.GPSLatitude.value[0].asFloat() +
- (1 / 60) * this.gps.GPSLatitude.value[1].asFloat() +
- (1 / 3600) * this.gps.GPSLatitude.value[2].asFloat();
- if (this.gps.GPSLatitudeRef.value === "S") {
- latitude = -latitude;
- }
- this.gps._addProperty("latitude", "Dec. Latitude", latitude);
- }
- if (this.gps.GPSLongitude) {
- var longitude;
- longitude = this.gps.GPSLongitude.value[0].asFloat() +
- (1 / 60) * this.gps.GPSLongitude.value[1].asFloat() +
- (1 / 3600) * this.gps.GPSLongitude.value[2].asFloat();
- if (this.gps.GPSLongitudeRef.value === "W") {
- longitude = -longitude;
- }
- this.gps._addProperty("longitude", "Dec. Longitude", longitude);
- }
- }
- };
-
- // MediaWiki: Export as module
- module.exports = function( fileReaderResult, fileName ) {
- return new JpegMeta.JpegFile( fileReaderResult, fileName );
- };
-
- // MediaWiki: Add mw.libs wrapper
- // @deprecated since 1.31
- mw.log.deprecate( mw.libs, 'jpegmeta', module.exports );
-
-}( mediaWiki ) );
if ( meta && meta.tiff && meta.tiff.Orientation ) {
rotation = ( 360 - ( function () {
- // See includes/media/Bitmap.php
+ // See BitmapHandler class in PHP
switch ( meta.tiff.Orientation.value ) {
case 8:
return 90;
function updateCount() {
var remaining = limit - byteLength( textInputWidget.getValue() );
- remaining = mw.language.convertNumber( remaining );
+ if ( remaining > 99 ) {
+ remaining = '';
+ } else {
+ remaining = mw.language.convertNumber( remaining );
+ }
textInputWidget.setLabel( remaining );
}
textInputWidget.on( 'change', updateCount );
function updateCount() {
var remaining = limit - codePointLength( textInputWidget.getValue() );
- remaining = mw.language.convertNumber( remaining );
+ if ( remaining > 99 ) {
+ remaining = '';
+ } else {
+ remaining = mw.language.convertNumber( remaining );
+ }
textInputWidget.setLabel( remaining );
}
textInputWidget.on( 'change', updateCount );
* @return {jQuery.Promise} Received token.
*/
getToken: function ( type, assert ) {
- var apiPromise, promiseGroup, d;
+ var apiPromise, promiseGroup, d, reject;
type = mapLegacyToken( type );
promiseGroup = promises[ this.defaults.ajax.url ];
d = promiseGroup && promiseGroup[ type + 'Token' ];
type: type,
assert: assert
} );
+ reject = function () {
+ // Clear promise. Do not cache errors.
+ delete promiseGroup[ type + 'Token' ];
+
+ // Let caller handle the error code
+ return $.Deferred().rejectWith( this, arguments );
+ };
d = apiPromise
.then( function ( res ) {
+ if ( !res.query ) {
+ return reject( 'query-missing', res );
+ }
// If token type is unknown, it is omitted from the response
if ( !res.query.tokens[ type + 'token' ] ) {
return $.Deferred().reject( 'token-missing', res );
}
-
return res.query.tokens[ type + 'token' ];
- }, function () {
- // Clear promise. Do not cache errors.
- delete promiseGroup[ type + 'Token' ];
-
- // Let caller handle the error code
- return $.Deferred().rejectWith( this, arguments );
- } )
+ }, reject )
// Attach abort handler
.promise( { abort: apiPromise.abort } );
line-height: 1.4;
}
+.mw-feedbackDialog-feedback-terms p:first-child {
+ margin-top: 0;
+}
+
.mw-feedbackDialog-welcome-message {
margin-bottom: 1em;
}
};
/**
- * Returns a function suitable for use as a global, to construct strings from the message key (and optional replacements).
- * e.g.
+ * Returns a function suitable for static use, to construct strings from a message key (and optional replacements).
+ *
+ * Example:
*
- * window.gM = mediaWiki.jqueryMsg.getMessageFunction( options );
- * $( 'p#headline' ).html( gM( 'hello-user', username ) );
+ * var format = mediaWiki.jqueryMsg.getMessageFunction( options );
+ * $( '#example' ).text( format( 'hello-user', username ) );
*
- * Like the old gM() function this returns only strings, so it destroys any bindings. If you want to preserve bindings use the
- * jQuery plugin version instead. This is only included for backwards compatibility with gM().
+ * Tthis returns only strings, so it destroys any bindings. If you want to preserve bindings, use the
+ * jQuery plugin version instead. This was originally created to ease migration from `window.gM()`,
+ * from a time when the parser used by `mw.message` was not extendable.
*
* N.B. replacements are variadic arguments or an array in second parameter. In other words:
* somefunction( a, b, c, d )
* somefunction( a, [b, c, d] )
*
* @param {Object} options parser options
- * @return {Function} Function suitable for assigning to window.gM
+ * @return {Function} Function The message formatter
* @return {string} return.key Message key.
* @return {Array|Mixed} return.replacements Optional variable replacements (variadically or an array).
* @return {string} return.return Rendered HTML.
}
};
- // Deprecated! don't rely on gM existing.
- // The window.gM ought not to be required - or if required, not required here.
- // But moving it to extensions breaks it (?!)
- // Need to fix plugin so it could do attributes as well, then will be okay to remove this.
- // @deprecated since 1.23
- mw.log.deprecate( window, 'gM', mw.jqueryMsg.getMessageFunction(), 'Use mw.message( ... ).parse() instead.' );
-
/**
* @method
* @member jQuery
* 'moduleName': {
* // From mw.loader.register()
* 'version': '########' (hash)
- * 'dependencies': ['required.foo', 'bar.also', ...], (or) function () {}
+ * 'dependencies': ['required.foo', 'bar.also', ...]
* 'group': 'somegroup', (or) null
* 'source': 'local', (or) 'anotherwiki'
* 'skip': 'return !!window.Example', (or) null
*/
jobs = [],
- // For getMarker()
- marker = null,
+ /**
+ * For #addEmbeddedCSS() and #addLink()
+ *
+ * @private
+ * @property {HTMLElement|null} marker
+ */
+ marker = document.querySelector( 'meta[name="ResourceLoaderDynamicStyles"]' ),
// For addEmbeddedCSS()
cssBuffer = '',
cssBufferTimer = null,
- cssCallbacks = $.Callbacks(),
+ cssCallbacks = [],
rAF = window.requestAnimationFrame || setTimeout;
- function getMarker() {
- if ( !marker ) {
- // Cache
- marker = document.querySelector( 'meta[name="ResourceLoaderDynamicStyles"]' );
- if ( !marker ) {
- mw.log( 'Created ResourceLoaderDynamicStyles marker dynamically' );
- marker = document.createElement( 'meta' );
- marker.name = 'ResourceLoaderDynamicStyles';
- document.head.appendChild( marker );
- }
- }
- return marker;
- }
-
/**
* Create a new style element and add it to the DOM.
*
* @private
* @param {string} text CSS text
- * @param {Node} [nextNode] The element where the style tag
+ * @param {Node|null} [nextNode] The element where the style tag
* should be inserted before
* @return {HTMLElement} Reference to the created style element
*/
function newStyleTag( text, nextNode ) {
- var s = document.createElement( 'style' );
-
- s.appendChild( document.createTextNode( text ) );
+ var el = document.createElement( 'style' );
+ el.appendChild( document.createTextNode( text ) );
if ( nextNode && nextNode.parentNode ) {
- nextNode.parentNode.insertBefore( s, nextNode );
+ nextNode.parentNode.insertBefore( el, nextNode );
} else {
- document.head.appendChild( s );
+ document.head.appendChild( el );
}
-
- return s;
+ return el;
}
/**
*/
function addEmbeddedCSS( cssText, callback ) {
function fireCallbacks() {
- var oldCallbacks = cssCallbacks;
+ var i,
+ oldCallbacks = cssCallbacks;
// Reset cssCallbacks variable so it's not polluted by any calls to
// addEmbeddedCSS() from one of the callbacks (T105973)
- cssCallbacks = $.Callbacks();
- oldCallbacks.fire().empty();
+ cssCallbacks = [];
+ for ( i = 0; i < oldCallbacks.length; i++ ) {
+ oldCallbacks[ i ]();
+ }
}
if ( callback ) {
- cssCallbacks.add( callback );
+ cssCallbacks.push( callback );
}
// Yield once before creating the <style> tag. This lets multiple stylesheets
cssBuffer = '';
}
- $( newStyleTag( cssText, getMarker() ) );
+ newStyleTag( cssText, marker );
fireCallbacks();
}
}
}
- // Resolves dynamic loader function and replaces it with its own results
- if ( typeof registry[ module ].dependencies === 'function' ) {
- registry[ module ].dependencies = registry[ module ].dependencies();
- // Ensures the module's dependencies are always in an array
- if ( typeof registry[ module ].dependencies !== 'object' ) {
- registry[ module ].dependencies = [ registry[ module ].dependencies ];
- }
- }
if ( resolved.indexOf( module ) !== -1 ) {
// Module already resolved; nothing to do
return;
// see #addEmbeddedCSS, T33676, T43331, and T49277 for details.
el.href = url;
- $( getMarker() ).before( el );
+ if ( marker && marker.parentNode ) {
+ marker.parentNode.insertBefore( el, marker );
+ } else {
+ document.head.appendChild( el );
+ }
}
/**
* a list of arguments compatible with this method
* @param {string|number} version Module version hash (falls backs to empty string)
* Can also be a number (timestamp) for compatibility with MediaWiki 1.25 and earlier.
- * @param {string|Array|Function} dependencies One string or array of strings of module
- * names on which this module depends, or a function that returns that array.
+ * @param {string|Array} dependencies One string or array of strings of module
+ * names on which this module depends.
* @param {string} [group=null] Group which the module is in
* @param {string} [source='local'] Name of the source
* @param {string} [skip=null] Script body of the skip function
if ( typeof dependencies === 'string' ) {
// A single module name
deps = [ dependencies ];
- } else if ( typeof dependencies === 'object' || typeof dependencies === 'function' ) {
- // Array of module names or a function that returns an array
+ } else if ( typeof dependencies === 'object' ) {
+ // Array of module names
deps = dependencies;
}
// List the module as registered
return $.when.apply( $, all );
} );
loading.then( function () {
- /* global mwPerformance */
- mwPerformance.mark( 'mwLoadEnd' );
+ if ( window.performance && performance.mark ) {
+ performance.mark( 'mwLoadEnd' );
+ }
mw.hook( 'resourceloader.loadEnd' ).fire();
} );
} );
+++ /dev/null
-.mw-headline-anchor {
- display: none;
-}
switch ( mode ) {
case 'html5':
return str.replace( / /g, '_' );
- case 'html5-legacy':
- str = str.replace( /[ \t\n\r\f_'"&#%]+/g, '_' )
- .replace( /^_+|_+$/, '' );
- if ( str === '' ) {
- str = '_';
- }
- return str;
case 'legacy':
return rawurlencode( str.replace( / /g, '_' ) )
.replace( /%3A/g, ':' )
}
};
- /**
- * @method wikiGetlink
- * @inheritdoc #getUrl
- * @deprecated since 1.23 Use #getUrl instead.
- */
- mw.log.deprecate( util, 'wikiGetlink', util.getUrl, 'Use mw.util.getUrl instead.', 'mw.util.wikiGetlink' );
-
/**
* Add the appropriate prefix to the accesskey shown in the tooltip.
*
+++ /dev/null
-// Use DMY date format for Moment.js, in accordance with MediaWiki's date formatting routines.
-// This affects English only (and languages without localisations, that fall back to English).
-// http://momentjs.com/docs/#/customization/long-date-formats/
-/* global moment */
-moment.updateLocale( 'en', {
- longDateFormat: {
- // Unchanged, but have to be repeated here:
- LT: 'h:mm A',
- LTS: 'h:mm:ss A',
- // Customized:
- L: 'DD/MM/YYYY',
- LL: 'D MMMM YYYY',
- LLL: 'D MMMM YYYY LT',
- LLLL: 'dddd, D MMMM YYYY LT'
- }
-} );
+++ /dev/null
-// Back-compat: Export module as global
-window.moment = module.exports;
+++ /dev/null
-/* global mediaWiki, moment */
-
-( function ( mw ) {
- // HACK: Overwrite moment's i18n with MediaWiki's for the current language so that
- // wgTranslateNumerals is respected.
- moment.updateLocale( moment.locale(), {
- preparse: function ( s ) {
- var i,
- table = mw.language.getDigitTransformTable();
- if ( mw.config.get( 'wgTranslateNumerals' ) ) {
- for ( i = 0; i < 10; i++ ) {
- if ( table[ i ] !== undefined ) {
- s = s.replace( new RegExp( mw.RegExp.escape( table[ i ] ), 'g' ), i );
- }
- }
- }
- // HACK: momentjs replaces commas in some languages, which is the only other use of preparse
- // aside from digit transformation. We can only override preparse, not extend it, so we
- // have to replicate the comma replacement functionality here.
- if ( [ 'ar', 'ar-sa', 'fa' ].indexOf( mw.config.get( 'wgUserLanguage' ) ) !== -1 ) {
- s = s.replace( /،/g, ',' );
- }
- return s;
- },
- postformat: function ( s ) {
- var i,
- table = mw.language.getDigitTransformTable();
- if ( mw.config.get( 'wgTranslateNumerals' ) ) {
- for ( i = 0; i < 10; i++ ) {
- if ( table[ i ] !== undefined ) {
- s = s.replace( new RegExp( i, 'g' ), table[ i ] );
- }
- }
- }
- // HACK: momentjs replaces commas in some languages, which is the only other use of postformat
- // aside from digit transformation. We can only override postformat, not extend it, so we
- // have to replicate the comma replacement functionality here.
- if ( [ 'ar', 'ar-sa', 'fa' ].indexOf( mw.config.get( 'wgUserLanguage' ) ) !== -1 ) {
- s = s.replace( /,/g, '،' );
- }
- return s;
- }
- } );
-}( mediaWiki ) );
--- /dev/null
+// Use DMY date format for Moment.js, in accordance with MediaWiki's date formatting routines.
+// This affects English only (and languages without localisations, that fall back to English).
+// http://momentjs.com/docs/#/customization/long-date-formats/
+/* global moment */
+moment.updateLocale( 'en', {
+ longDateFormat: {
+ // Unchanged, but have to be repeated here:
+ LT: 'h:mm A',
+ LTS: 'h:mm:ss A',
+ // Customized:
+ L: 'DD/MM/YYYY',
+ LL: 'D MMMM YYYY',
+ LLL: 'D MMMM YYYY LT',
+ LLLL: 'dddd, D MMMM YYYY LT'
+ }
+} );
--- /dev/null
+// Back-compat: Export module as global
+window.moment = module.exports;
--- /dev/null
+/* global mediaWiki, moment */
+
+( function ( mw ) {
+ // HACK: Overwrite moment's i18n with MediaWiki's for the current language so that
+ // wgTranslateNumerals is respected.
+ moment.updateLocale( moment.locale(), {
+ preparse: function ( s ) {
+ var i,
+ table = mw.language.getDigitTransformTable();
+ if ( mw.config.get( 'wgTranslateNumerals' ) ) {
+ for ( i = 0; i < 10; i++ ) {
+ if ( table[ i ] !== undefined ) {
+ s = s.replace( new RegExp( mw.RegExp.escape( table[ i ] ), 'g' ), i );
+ }
+ }
+ }
+ // HACK: momentjs replaces commas in some languages, which is the only other use of preparse
+ // aside from digit transformation. We can only override preparse, not extend it, so we
+ // have to replicate the comma replacement functionality here.
+ if ( [ 'ar', 'ar-sa', 'fa' ].indexOf( mw.config.get( 'wgUserLanguage' ) ) !== -1 ) {
+ s = s.replace( /،/g, ',' );
+ }
+ return s;
+ },
+ postformat: function ( s ) {
+ var i,
+ table = mw.language.getDigitTransformTable();
+ if ( mw.config.get( 'wgTranslateNumerals' ) ) {
+ for ( i = 0; i < 10; i++ ) {
+ if ( table[ i ] !== undefined ) {
+ s = s.replace( new RegExp( i, 'g' ), table[ i ] );
+ }
+ }
+ }
+ // HACK: momentjs replaces commas in some languages, which is the only other use of postformat
+ // aside from digit transformation. We can only override postformat, not extend it, so we
+ // have to replicate the comma replacement functionality here.
+ if ( [ 'ar', 'ar-sa', 'fa' ].indexOf( mw.config.get( 'wgUserLanguage' ) ) !== -1 ) {
+ s = s.replace( /,/g, '،' );
+ }
+ return s;
+ }
+ } );
+}( mediaWiki ) );
* - Beware: Do not call mwNow before the isCompatible() check.
*/
-/* global mw, mwPerformance, mwNow, isCompatible, $VARS, $CODE */
+/* global mw, mwNow, isCompatible, $VARS, $CODE */
-window.mwPerformance = ( window.performance && performance.mark ) ? performance : {
- mark: function () {}
-};
// Define now() here to ensure valid comparison with mediaWikiLoadEnd (T153819).
window.mwNow = ( function () {
var perf = window.performance,
}
window.mediaWikiLoadStart = mwNow();
- mwPerformance.mark( 'mwLoadStart' );
-
+ if ( window.performance && performance.mark ) {
+ performance.mark( 'mwStartup' );
+ }
script = document.createElement( 'script' );
script.src = $VARS.baseModulesUri;
script.onload = function () {
$setup['wgNoFollowLinks'] = true;
$setup['wgNoFollowDomainExceptions'] = [ 'no-nofollow.org' ];
$setup['wgExternalLinkTarget'] = false;
- $setup['wgExperimentalHtmlIds'] = false;
$setup['wgLocaltimezone'] = 'UTC';
$setup['wgHtml5'] = true;
$setup['wgDisableLangConversion'] = false;
$teardown[] = $this->markSetupDone( 'setupDatabase' );
# CREATE TEMPORARY TABLE breaks if there is more than one server
- if ( wfGetLB()->getServerCount() != 1 ) {
+ if ( MediaWikiServices::getInstance()->getDBLoadBalancer()->getServerCount() != 1 ) {
$this->useTemporaryTables = false;
}
'maintenance/',
'mw-config/',
'resources/',
- 'skins/',
'vendor/',
],
'maintenance/language/',
// External class
'includes/libs/jsminplus.php',
- // separate repositories
- 'skins/',
],
/**
/**
* Integration test to catch regressions like T74870. Taken and modified
* from SemanticMediaWiki
+ *
+ * @covers Title::moveTo
*/
public function testTitleMoveCompleteIntegrationTest() {
$oldTitle = Title::newFromText( 'Help:Some title' );
/**
* @dataProvider provideCdnCacheEpoch
+ * @covers OutputPage::getCdnCacheEpoch
*/
public function testCdnCacheEpoch( $params ) {
$out = TestingAccessWrapper::newFromObject( $this->newInstance() );
<?php
+/**
+ * @coversNothing Just a sample
+ */
class SampleTest extends MediaWikiLangTestCase {
/**
*/
public function testNewMutableRevisionFromArray_legacyEncoding( array $array ) {
$cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
- $blobStore = new SqlBlobStore( wfGetLB(), $cache );
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+ $blobStore = new SqlBlobStore( $lb, $cache );
$blobStore->setLegacyEncoding( 'windows-1252', Language::factory( 'en' ) );
$factory = $this->getMockBuilder( BlobStoreFactory::class )
*/
public function testNewRevisionFromRow_legacyEncoding_applied( $encoding, $locale, $row, $text ) {
$cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
- $blobStore = new SqlBlobStore( wfGetLB(), $cache );
+ $blobStore = new SqlBlobStore( $lb, $cache );
$blobStore->setLegacyEncoding( $encoding, Language::factory( $locale ) );
- $store = $this->getRevisionStore( wfGetLB(), $blobStore, $cache );
+ $store = $this->getRevisionStore( $lb, $blobStore, $cache );
$record = $store->newRevisionFromRow(
$this->makeRow( $row ),
];
$cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
- $blobStore = new SqlBlobStore( wfGetLB(), $cache );
+ $blobStore = new SqlBlobStore( $lb, $cache );
$blobStore->setLegacyEncoding( 'windows-1252', Language::factory( 'en' ) );
- $store = $this->getRevisionStore( wfGetLB(), $blobStore, $cache );
+ $store = $this->getRevisionStore( $lb, $blobStore, $cache );
$record = $store->newRevisionFromRow(
$this->makeRow( $row ),
->getMock();
$skin->expects( $this->once() )->method( 'getDefaultModules' )
->willReturn( [
+ 'styles' => [ 'core' => [ 'quux.styles' ] ],
'core' => [ 'foo', 'bar' ],
'content' => [ 'baz' ]
] );
'resp.parse.modulescripts'
);
$this->assertSame(
- [ 'foo.styles' ],
+ [ 'foo.styles', 'quux.styles' ],
$res[0]['parse']['modulestyles'],
'resp.parse.modulestyles'
);
use Psr\Log\LoggerInterface;
use Wikimedia\TestingAccessWrapper;
+/**
+ * @covers \MediaWiki\Auth\EmailNotificationSecondaryAuthenticationProvider
+ */
class EmailNotificationSecondaryAuthenticationProviderTest extends \PHPUnit\Framework\TestCase {
public function testConstructor() {
$config = new \HashConfig( [
global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir;
$factory = new LBFactoryMulti( [
- 'sectionsByDB' => [],
+ 'sectionsByDB' => [
+ 's1wiki' => 's1',
+ ],
'sectionLoads' => [
+ 's1' => [
+ 'test-db3' => 0,
+ 'test-db4' => 100,
+ ],
'DEFAULT' => [
'test-db1' => 0,
'test-db2' => 100,
- ],
+ ]
],
'serverTemplate' => [
'dbname' => $wgDBname,
],
'hostsByName' => [
'test-db1' => $wgDBserver,
- 'test-db2' => $wgDBserver
+ 'test-db2' => $wgDBserver,
+ 'test-db3' => $wgDBserver,
+ 'test-db4' => $wgDBserver
],
'loadMonitorClass' => LoadMonitorNull::class
] );
$dbr = $lb->getConnection( DB_REPLICA );
$this->assertTrue( $dbr->getLBInfo( 'replica' ), 'slave shows as slave' );
+ // Test that LoadBalancer instances made during commitMasterChanges() do not throw
+ // DBTransactionError due to transaction ROUND_* stages being mismatched.
+ $factory->beginMasterChanges( __METHOD__ );
+ $dbw->onTransactionPreCommitOrIdle( function () use ( $factory ) {
+ // Trigger s1 LoadBalancer instantiation during "finalize" stage.
+ // There is no s1wiki DB to select so it is not in getConnection(),
+ // but this fools getMainLB() at least.
+ $factory->getMainLB( 's1wiki' )->getConnection( DB_MASTER );
+ } );
+ $factory->commitMasterChanges( __METHOD__ );
+
+ $count = 0;
+ $factory->forEachLB( function () use ( &$count ) {
+ ++$count;
+ } );
+ $this->assertEquals( 2, $count );
+
$factory->shutdown();
- $lb->closeAll();
+ $factory->closeAll();
}
/**
$lb->closeAll();
}
+
+ public function testTransactionCallbackChains() {
+ global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir;
+
+ $servers = [
+ [
+ 'host' => $wgDBserver,
+ 'dbname' => $wgDBname,
+ 'tablePrefix' => $this->dbPrefix(),
+ 'user' => $wgDBuser,
+ 'password' => $wgDBpassword,
+ 'type' => $wgDBtype,
+ 'dbDirectory' => $wgSQLiteDataDir,
+ 'load' => 0,
+ 'flags' => DBO_TRX // REPEATABLE-READ for consistency
+ ],
+ ];
+
+ $lb = new LoadBalancer( [
+ 'servers' => $servers,
+ 'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() )
+ ] );
+
+ $conn1 = $lb->openConnection( $lb->getWriterIndex(), false );
+ $conn2 = $lb->openConnection( $lb->getWriterIndex(), '' );
+
+ $count = 0;
+ $lb->forEachOpenMasterConnection( function () use ( &$count ) {
+ ++$count;
+ } );
+ $this->assertEquals( 2, $count, 'Connection handle count' );
+
+ $tlCalls = 0;
+ $lb->setTransactionListener( 'test-listener', function () use ( &$tlCalls ) {
+ ++$tlCalls;
+ } );
+
+ $lb->beginMasterChanges( __METHOD__ );
+ $bc = array_fill_keys( [ 'a', 'b', 'c', 'd' ], 0 );
+ $conn1->onTransactionPreCommitOrIdle( function () use ( &$bc, $conn1, $conn2 ) {
+ $bc['a'] = 1;
+ $conn2->onTransactionPreCommitOrIdle( function () use ( &$bc, $conn1, $conn2 ) {
+ $bc['b'] = 1;
+ $conn1->onTransactionPreCommitOrIdle( function () use ( &$bc, $conn1, $conn2 ) {
+ $bc['c'] = 1;
+ $conn1->onTransactionPreCommitOrIdle( function () use ( &$bc, $conn1, $conn2 ) {
+ $bc['d'] = 1;
+ } );
+ } );
+ } );
+ } );
+ $lb->finalizeMasterChanges();
+ $lb->approveMasterChanges( [] );
+ $lb->commitMasterChanges( __METHOD__ );
+ $lb->runMasterTransactionIdleCallbacks();
+ $lb->runMasterTransactionListenerCallbacks();
+
+ $this->assertEquals( array_fill_keys( [ 'a', 'b', 'c', 'd' ], 1 ), $bc );
+ $this->assertEquals( 2, $tlCalls );
+
+ $tlCalls = 0;
+ $lb->beginMasterChanges( __METHOD__ );
+ $ac = array_fill_keys( [ 'a', 'b', 'c', 'd' ], 0 );
+ $conn1->onTransactionIdle( function () use ( &$ac, $conn1, $conn2 ) {
+ $ac['a'] = 1;
+ $conn2->onTransactionIdle( function () use ( &$ac, $conn1, $conn2 ) {
+ $ac['b'] = 1;
+ $conn1->onTransactionIdle( function () use ( &$ac, $conn1, $conn2 ) {
+ $ac['c'] = 1;
+ $conn1->onTransactionIdle( function () use ( &$ac, $conn1, $conn2 ) {
+ $ac['d'] = 1;
+ } );
+ } );
+ } );
+ } );
+ $lb->finalizeMasterChanges();
+ $lb->approveMasterChanges( [] );
+ $lb->commitMasterChanges( __METHOD__ );
+ $lb->runMasterTransactionIdleCallbacks();
+ $lb->runMasterTransactionListenerCallbacks();
+
+ $this->assertEquals( array_fill_keys( [ 'a', 'b', 'c', 'd' ], 1 ), $ac );
+ $this->assertEquals( 2, $tlCalls );
+
+ $conn1->close();
+ $conn2->close();
+ }
}
$this->assertSame( 1, $ran, 'Update ran' );
}
+
+ /**
+ * @covers DeferredUpdates::tryOpportunisticExecute
+ */
+ public function testTryOpportunisticExecute() {
+ $calls = [];
+ $callback1 = function () use ( &$calls ) {
+ $calls[] = 1;
+ };
+ $callback2 = function () use ( &$calls ) {
+ $calls[] = 2;
+ };
+
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $lbFactory->beginMasterChanges( __METHOD__ );
+
+ DeferredUpdates::addCallableUpdate( $callback1 );
+ $this->assertEquals( [], $calls );
+
+ DeferredUpdates::tryOpportunisticExecute( 'run' );
+ $this->assertEquals( [], $calls );
+
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->onTransactionIdle( function () use ( &$calls, $callback2 ) {
+ DeferredUpdates::addCallableUpdate( $callback2 );
+ $this->assertEquals( [], $calls );
+ $calls[] = 'oti';
+ } );
+ $this->assertEquals( 1, $dbw->trxLevel() );
+ $this->assertEquals( [], $calls );
+
+ $lbFactory->commitMasterChanges( __METHOD__ );
+
+ $this->assertEquals( [ 'oti' ], $calls );
+
+ DeferredUpdates::tryOpportunisticExecute( 'run' );
+ $this->assertEquals( [ 'oti', 1, 2 ], $calls );
+ }
}
[ 'background-image: url("");', false, '/example', false ],
'background-image: url("");',
],
+ 'Single quote with outer spacing' => [
+ [ "background-image: url( '' );", false, '/example', false ],
+ "background-image: url( '' );",
+ ],
];
}
'foo { background: url(/static/foo.png?query=yes); }',
'foo { background: url(https://expand.example/static/foo.png?query=yes); }',
],
+ [
+ 'Path-relative URL with query',
+ "foo { background: url(?query=yes); }",
+ 'foo { background: url(http://localhost/w/?query=yes); }',
+ ],
[
'Remote URL (unnecessary quotes not preserved)',
'foo { background: url("http://example.org/w/unnecessary-quotes.png"); }',
'foo { background: url( "http://localhost/styles.css?quoted=double" ) }',
'foo { background: url(http://localhost/styles.css?quoted=double) }',
],
+ [
+ 'Background URL (single quoted, containing spaces, with outer spacing)',
+ "foo { background: url( ' red.gif ' ); }",
+ 'foo { background: url("http://localhost/w/ red.gif "); }',
+ ],
[
'Simple case with comments before url',
'foo { prop: /* some {funny;} comment */ url(bar.png); }',
use Wikimedia\Rdbms\DatabaseSqlite;
use Wikimedia\Rdbms\DatabasePostgres;
use Wikimedia\Rdbms\DatabaseMssql;
+use Wikimedia\Rdbms\DBUnexpectedError;
class DatabaseTest extends PHPUnit\Framework\TestCase {
$called = true;
$db->setFlag( DBO_TRX );
} );
- $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
+ $db->rollback( __METHOD__ );
$this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
$this->assertTrue( $called, 'Callback reached' );
}
$this->assertEquals( true, $db->lockIsFree( 'x', __METHOD__ ) );
$db->clearFlag( DBO_TRX );
+ // Pending writes with DBO_TRX
$this->assertEquals( 0, $db->trxLevel() );
-
+ $this->assertTrue( $db->lockIsFree( 'meow', __METHOD__ ) );
$db->setFlag( DBO_TRX );
+ $db->query( "DELETE FROM test WHERE t = 1" ); // trigger DBO_TRX transaction before lock
try {
- $this->badLockingMethodImplicit( $db );
- } catch ( RunTimeException $e ) {
- $this->assertTrue( $db->trxLevel() > 0, "Transaction not committed." );
+ $lock = $db->getScopedLockAndFlush( 'meow', __METHOD__, 1 );
+ $this->fail( "Exception not reached" );
+ } catch ( DBUnexpectedError $e ) {
+ $this->assertEquals( 1, $db->trxLevel(), "Transaction not committed." );
+ $this->assertTrue( $db->lockIsFree( 'meow', __METHOD__ ), 'Lock not acquired' );
}
- $db->clearFlag( DBO_TRX );
$db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
- $this->assertTrue( $db->lockIsFree( 'meow', __METHOD__ ) );
-
+ // Pending writes without DBO_TRX
+ $db->clearFlag( DBO_TRX );
+ $this->assertEquals( 0, $db->trxLevel() );
+ $this->assertTrue( $db->lockIsFree( 'meow2', __METHOD__ ) );
+ $db->begin( __METHOD__ );
+ $db->query( "DELETE FROM test WHERE t = 1" ); // trigger DBO_TRX transaction before lock
try {
- $this->badLockingMethodExplicit( $db );
- } catch ( RunTimeException $e ) {
- $this->assertTrue( $db->trxLevel() > 0, "Transaction not committed." );
+ $lock = $db->getScopedLockAndFlush( 'meow2', __METHOD__, 1 );
+ $this->fail( "Exception not reached" );
+ } catch ( DBUnexpectedError $e ) {
+ $this->assertEquals( 1, $db->trxLevel(), "Transaction not committed." );
+ $this->assertTrue( $db->lockIsFree( 'meow2', __METHOD__ ), 'Lock not acquired' );
}
+ $db->rollback( __METHOD__ );
+ // No pending writes, with DBO_TRX
+ $db->setFlag( DBO_TRX );
+ $this->assertEquals( 0, $db->trxLevel() );
+ $this->assertTrue( $db->lockIsFree( 'wuff', __METHOD__ ) );
+ $db->query( "SELECT 1", __METHOD__ );
+ $this->assertEquals( 1, $db->trxLevel() );
+ $lock = $db->getScopedLockAndFlush( 'wuff', __METHOD__, 1 );
+ $this->assertEquals( 0, $db->trxLevel() );
+ $this->assertFalse( $db->lockIsFree( 'wuff', __METHOD__ ), 'Lock already acquired' );
$db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
- $this->assertTrue( $db->lockIsFree( 'meow', __METHOD__ ) );
- }
-
- private function badLockingMethodImplicit( IDatabase $db ) {
- $lock = $db->getScopedLockAndFlush( 'meow', __METHOD__, 1 );
- $db->query( "SELECT 1" ); // trigger DBO_TRX
- throw new RunTimeException( "Uh oh!" );
- }
-
- private function badLockingMethodExplicit( IDatabase $db ) {
- $lock = $db->getScopedLockAndFlush( 'meow', __METHOD__, 1 );
+ // No pending writes, without DBO_TRX
+ $db->clearFlag( DBO_TRX );
+ $this->assertEquals( 0, $db->trxLevel() );
+ $this->assertTrue( $db->lockIsFree( 'wuff2', __METHOD__ ) );
$db->begin( __METHOD__ );
- throw new RunTimeException( "Uh oh!" );
+ try {
+ $lock = $db->getScopedLockAndFlush( 'wuff2', __METHOD__, 1 );
+ $this->fail( "Exception not reached" );
+ } catch ( DBUnexpectedError $e ) {
+ $this->assertEquals( 1, $db->trxLevel(), "Transaction not committed." );
+ $this->assertFalse( $db->lockIsFree( 'wuff2', __METHOD__ ), 'Lock not acquired' );
+ }
+ $db->rollback( __METHOD__ );
}
/**
$formatter->setShowUserToolLinks( false );
$paramsWithoutTools = $formatter->getMessageParametersForTesting();
- unset( $formatter->parsedParameters );
- $formatter->setShowUserToolLinks( true );
- $paramsWithTools = $formatter->getMessageParametersForTesting();
+ $formatter2 = LogFormatter::newFromEntry( $entry );
+ $formatter2->setContext( $this->context );
+ $formatter2->setShowUserToolLinks( true );
+ $paramsWithTools = $formatter2->getMessageParametersForTesting();
$userLink = Linker::userLink(
$this->user->getId(),
$legacyEncoded = 'foo_.D1.82.D0.B5.D1.81.D1.82_.23.25.21.27.28.29.5B.5D:.3C.3E' .
'.26.26amp.3B.26amp.3Bamp.3B';
$html5Encoded = 'foo_тест_#%!\'()[]:<>&&&amp;';
- $html5Experimental = 'foo_тест_!_()[]:<>_amp;_amp;amp;';
// Settings: last element is $wgExternalInterwikiFragmentMode, the rest is $wgFragmentMode
$legacy = [ 'legacy', 'legacy' ];
$newLegacy = [ 'html5', 'legacy', 'legacy' ];
$new = [ 'html5', 'legacy' ];
$allNew = [ 'html5', 'html5' ];
- $experimentalLegacy = [ 'html5-legacy', 'legacy', 'legacy' ];
- $newExperimental = [ 'html5', 'html5-legacy', 'legacy' ];
return [
// Pure legacy: how MW worked before 2017
[ 'Attribute', $allNew, $text, false, Sanitizer::ID_FALLBACK ],
[ 'Link', $allNew, $text, $html5Encoded ],
[ 'ExternalInterwiki', $allNew, $text, $html5Encoded ],
-
- // Someone flipped $wgExperimentalHtmlIds on
- [ 'Attribute', $experimentalLegacy, $text, $html5Experimental, Sanitizer::ID_PRIMARY ],
- [ 'Attribute', $experimentalLegacy, $text, $legacyEncoded, Sanitizer::ID_FALLBACK ],
- [ 'Link', $experimentalLegacy, $text, $html5Experimental ],
- [ 'ExternalInterwiki', $experimentalLegacy, $text, $legacyEncoded ],
-
- // Migration from $wgExperimentalHtmlIds to modern HTML5
- [ 'Attribute', $newExperimental, $text, $html5Encoded, Sanitizer::ID_PRIMARY ],
- [ 'Attribute', $newExperimental, $text, $html5Experimental, Sanitizer::ID_FALLBACK ],
- [ 'Link', $newExperimental, $text, $html5Encoded ],
- [ 'ExternalInterwiki', $newExperimental, $text, $legacyEncoded ],
];
}
/**
* The rclimit preference should accept non-integer input and filter it to become an integer.
+ *
+ * @covers \MediaWiki\Preferences\DefaultPreferencesFactory::saveFormData
*/
public function testIntvalFilter() {
// Test a string with leading zeros (i.e. not octal) and spaces.
/**
* @dataProvider provideGetStyles
- * @covers ResourceLoaderSkinModule::normalizeStyles
- * @covers ResourceLoaderSkinModule::getStyles
+ * @covers ResourceLoaderSkinModule
*/
public function testGetStyles( $parent, $logo, $expected ) {
$module = $this->getMockBuilder( ResourceLoaderSkinModule::class )
$resourceLoader->register( 'test', new stdClass() );
}
+ /**
+ * @covers ResourceLoader::register
+ */
+ public function testRegisterDuplicate() {
+ $logger = $this->getMockBuilder( Psr\Log\LoggerInterface::class )->getMock();
+ $logger->expects( $this->once() )
+ ->method( 'warning' );
+ $resourceLoader = new EmptyResourceLoader( null, $logger );
+
+ $module1 = new ResourceLoaderTestModule();
+ $module2 = new ResourceLoaderTestModule();
+ $resourceLoader->register( 'test', $module1 );
+ $resourceLoader->register( 'test', $module2 );
+ $this->assertSame( $module2, $resourceLoader->getModule( 'test' ) );
+ }
+
/**
* @covers ResourceLoader::getModuleNames
*/
<?php
+use MediaWiki\MediaWikiServices;
+
/**
* Tests for the DBSiteStore class.
*
private function newDBSiteStore() {
// NOTE: Use the real DB load balancer for now. Eventually, the test framework should
// provide a LoadBalancer that is safe to use in unit tests.
- return new DBSiteStore( wfGetLB() );
+ $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+ return new DBSiteStore( $lb );
}
/**
$mock->expects( $this->once() )
->method( 'isSyndicated' )
->will( $this->returnValue( $isSyndicated ) );
- $mock->expects( $this->once() )
+ $mock->expects( $this->any() )
->method( 'getHTML' )
->will( $this->returnValue( $html ) );
return $mock;
}
- public function provideSetupSkinUserCss() {
+ public function provideGetDefaultModules() {
$defaultStyles = [
'mediawiki.legacy.shared',
'mediawiki.legacy.commonPrint',
- 'mediawiki.sectionAnchor',
];
$buttonStyle = 'mediawiki.ui.button';
$feedStyle = 'mediawiki.feedlink';
return [
[
- $this->getMockOutputPage( false, '' ),
+ false,
+ '',
$defaultStyles
],
[
- $this->getMockOutputPage( true, '' ),
+ true,
+ '',
array_merge( $defaultStyles, [ $feedStyle ] )
],
[
- $this->getMockOutputPage( false, 'FOO mw-ui-button BAR' ),
+ false,
+ 'FOO mw-ui-button BAR',
array_merge( $defaultStyles, [ $buttonStyle ] )
],
[
- $this->getMockOutputPage( true, 'FOO mw-ui-button BAR' ),
- array_merge( $defaultStyles, [ $feedStyle, $buttonStyle ] )
+ true,
+ 'FOO mw-ui-button BAR',
+ array_merge( $defaultStyles, [ $buttonStyle, $feedStyle ] )
],
];
}
/**
- * @param PHPUnit_Framework_MockObject_MockObject|OutputPage $outputPageMock
- * @param string[] $expectedModuleStyles
- *
- * @covers SkinTemplate::setupSkinUserCss
- * @dataProvider provideSetupSkinUserCss
+ * @covers Skin::getDefaultModules
+ * @dataProvider provideGetDefaultModules
*/
- public function testSetupSkinUserCss( $outputPageMock, $expectedModuleStyles ) {
- $outputPageMock->expects( $this->once() )
- ->method( 'addModuleStyles' )
- ->with( $expectedModuleStyles );
+ public function testgetDefaultModules( $isSyndicated, $html, $expectedModuleStyles ) {
+ $skin = new SkinTemplate();
- $skinTemplate = new SkinTemplate();
- $skinTemplate->setupSkinUserCss( $outputPageMock );
+ $context = new DerivativeContext( $skin->getContext() );
+ $context->setOutput( $this->getMockOutputPage( $isSyndicated, $html ) );
+ $skin->setContext( $context );
+
+ $modules = $skin->getDefaultModules();
+
+ $actualStylesModule = call_user_func_array( 'array_merge', $modules['styles'] );
+ $this->assertArraySubset(
+ $expectedModuleStyles,
+ $actualStylesModule,
+ 'style modules'
+ );
}
}
$user = new TestUser( __METHOD__ );
list( $html, ) = $this->executeSpecialPage( 'clear', null, 'qqx', $user->getUser() );
$this->assertRegExp(
- '/<form class="mw-htmlform" action=".*?Special:EditWatchlist\/clear" method="post">/',
+ '/<form action=\'.*?Special:EditWatchlist\/clear\'/',
$html
);
}
$user = new TestUser( __METHOD__ );
list( $html, ) = $this->executeSpecialPage( 'raw', null, 'qqx', $user->getUser() );
$this->assertContains(
- '<textarea id="mw-input-wpTitles"',
+ '<div id=\'mw-input-wpTitles\'',
$html
);
}
"namespace Example;\nclass Foo {}\nclass_alias( Foo::class, 'Bar' );",
[ 'Example\Foo', 'Bar' ],
],
+ [
+ "new class() extends Foo {}",
+ []
+ ]
];
}
],
[ // recent problem words, part 1
[
- 'crh' => 'künü куню sürgünligi сюргюнлиги özü озю etti этти',
- 'crh-cyrl' => 'куню куню сюргюнлиги сюргюнлиги озю озю этти этти',
- 'crh-latn' => 'künü künü sürgünligi sürgünligi özü özü etti etti',
+ 'crh' => 'künü куню sürgünligi сюргюнлиги özü озю etti этти esas эсас dört дёрт',
+ 'crh-cyrl' => 'куню куню сюргюнлиги сюргюнлиги озю озю этти этти эсас эсас дёрт дёрт',
+ 'crh-latn' => 'künü künü sürgünligi sürgünligi özü özü etti etti esas esas dört dört',
],
- 'künü куню sürgünligi сюргюнлиги özü озю etti этти'
+ 'künü куню sürgünligi сюргюнлиги özü озю etti этти esas эсас dört дёрт'
],
[ // recent problem words, part 2
[
- 'crh' => 'esas эсас dört дёрт keldi кельди',
- 'crh-cyrl' => 'эсас эсас дёрт дёрт кельди кельди',
- 'crh-latn' => 'esas esas dört dört keldi keldi',
+ 'crh' => 'keldi кельди km² км² yüz юзь AQŞ АКъШ ŞSCBnen ШСДжБнен iyül июль',
+ 'crh-cyrl' => 'кельди кельди км² км² юзь юзь АКъШ АКъШ ШСДжБнен ШСДжБнен июль июль',
+ 'crh-latn' => 'keldi keldi km² km² yüz yüz AQŞ AQŞ ŞSCBnen ŞSCBnen iyül iyül',
],
- 'esas эсас dört дёрт keldi кельди'
+ 'keldi кельди km² км² yüz юзь AQŞ АКъШ ŞSCBnen ШСДжБнен iyül июль'
+ ],
+ [ // recent problem words, part 3
+ [
+ 'crh' => 'işğal ишгъаль işğalcilerine ишгъальджилерине rayon район üst усть',
+ 'crh-cyrl' => 'ишгъаль ишгъаль ишгъальджилерине ишгъальджилерине район район усть усть',
+ 'crh-latn' => 'işğal işğal işğalcilerine işğalcilerine rayon rayon üst üst',
+ ],
+ 'işğal ишгъаль işğalcilerine ишгъальджилерине rayon район üst усть'
+ ],
+ [ // recent problem words, part 4
+ [
+ 'crh' => 'rayonınıñ районынынъ Noğay Ногъай Yürtü Юрьтю vatandan ватандан',
+ 'crh-cyrl' => 'районынынъ районынынъ Ногъай Ногъай Юрьтю Юрьтю ватандан ватандан',
+ 'crh-latn' => 'rayonınıñ rayonınıñ Noğay Noğay Yürtü Yürtü vatandan vatandan',
+ ],
+ 'rayonınıñ районынынъ Noğay Ногъай Yürtü Юрьтю vatandan ватандан'
+ ],
+ [ // recent problem words, part 5
+ [
+ 'crh' => 'ком-кок köm-kök rol роль AQQI АКЪКЪЫ DAĞĞA ДАГЪГЪА 13-ünci 13-юнджи',
+ 'crh-cyrl' => 'ком-кок ком-кок роль роль АКЪКЪЫ АКЪКЪЫ ДАГЪГЪА ДАГЪГЪА 13-юнджи 13-юнджи',
+ 'crh-latn' => 'köm-kök köm-kök rol rol AQQI AQQI DAĞĞA DAĞĞA 13-ünci 13-ünci',
+ ],
+ 'ком-кок köm-kök rol роль AQQI АКЪКЪЫ DAĞĞA ДАГЪГЪА 13-ünci 13-юнджи'
+ ],
+ [ // recent problem words, part 6
+ [
+ 'crh' => 'ДЖУРЬМЕК CÜRMEK кетсин ketsin джумлеси cümlesi ильи ilyi Ильи İlyi',
+ 'crh-cyrl' => 'ДЖУРЬМЕК ДЖУРЬМЕК кетсин кетсин джумлеси джумлеси ильи ильи Ильи Ильи',
+ 'crh-latn' => 'CÜRMEK CÜRMEK ketsin ketsin cümlesi cümlesi ilyi ilyi İlyi İlyi',
+ ],
+ 'ДЖУРЬМЕК CÜRMEK кетсин ketsin джумлеси cümlesi ильи ilyi Ильи İlyi'
+ ],
+ [ // regex pattern words
+ [
+ 'crh' => 'köyünden коюнден ange аньге',
+ 'crh-cyrl' => 'коюнден коюнден аньге аньге',
+ 'crh-latn' => 'köyünden köyünden ange ange',
+ ],
+ 'köyünden коюнден ange аньге'
],
[ // multi part words
[
],
'эки юз eki yüz'
],
- [ // ALL CAPS, made up acronyms (not 100% sure these are correct)
+ [ // affix patterns
[
- 'crh' => 'ÑAB QIC ĞUK COT НЪАБ КЪЫДж ГЪУК ДЖОТ CA ДЖА',
- 'crh-cyrl' => 'НЪАБ КЪЫДж ГЪУК ДЖОТ НЪАБ КЪЫДж ГЪУК ДЖОТ ДЖА ДЖА',
+ 'crh' => 'köyniñ койнинъ Avcıköyde Авджыкойде ekvatorial экваториаль Canköy Джанкой',
+ 'crh-cyrl' => 'койнинъ койнинъ Авджыкойде Авджыкойде экваториаль экваториаль Джанкой Джанкой',
+ 'crh-latn' => 'köyniñ köyniñ Avcıköyde Avcıköyde ekvatorial ekvatorial Canköy Canköy',
+ ],
+ 'köyniñ койнинъ Avcıköyde Авджыкойде ekvatorial экваториаль Canköy Джанкой'
+ ],
+ [ // Roman numerals and quotes, esp. single-letter Roman numerals at the end of a string
+ [
+ 'crh' => 'VI,VII IX “dört” «дёрт» XI XII I V X L C D M',
+ 'crh-cyrl' => 'VI,VII IX «дёрт» «дёрт» XI XII I V X L C D M',
+ 'crh-latn' => 'VI,VII IX “dört” "dört" XI XII I V X L C D M',
+ ],
+ 'VI,VII IX “dört” «дёрт» XI XII I V X L C D M'
+ ],
+ [ // Roman numerals vs Initials, part 1 - Roman numeral initials without spaces
+ [
+ 'crh' => 'A.B.C.D.M. Qadırova XII, А.Б.Дж.Д.М. Къадырова XII',
+ 'crh-cyrl' => 'А.Б.Дж.Д.М. Къадырова XII, А.Б.Дж.Д.М. Къадырова XII',
+ 'crh-latn' => 'A.B.C.D.M. Qadırova XII, A.B.C.D.M. Qadırova XII',
+ ],
+ 'A.B.C.D.M. Qadırova XII, А.Б.Дж.Д.М. Къадырова XII'
+ ],
+ [ // Roman numerals vs Initials, part 2 - Roman numeral initials with spaces
+ [
+ 'crh' => 'G. H. I. V. X. L. Memetov III, Г. Х. Ы. В. X. Л. Меметов III',
+ 'crh-cyrl' => 'Г. Х. Ы. В. X. Л. Меметов III, Г. Х. Ы. В. X. Л. Меметов III',
+ 'crh-latn' => 'G. H. I. V. X. L. Memetov III, G. H. I. V. X. L. Memetov III',
+ ],
+ 'G. H. I. V. X. L. Memetov III, Г. Х. Ы. В. X. Л. Меметов III'
+ ],
+ [ // ALL CAPS, made up acronyms
+ [
+ 'crh' => 'ÑAB QIC ĞUK COT НЪАБ КЪЫДЖ ГЪУК ДЖОТ CA ДЖА',
+ 'crh-cyrl' => 'НЪАБ КЪЫДЖ ГЪУК ДЖОТ НЪАБ КЪЫДЖ ГЪУК ДЖОТ ДЖА ДЖА',
'crh-latn' => 'ÑAB QIC ĞUK COT ÑAB QIC ĞUK COT CA CA',
],
- 'ÑAB QIC ĞUK COT НЪАБ КЪЫДж ГЪУК ДЖОТ CA ДЖА'
+ 'ÑAB QIC ĞUK COT НЪАБ КЪЫДЖ ГЪУК ДЖОТ CA ДЖА'
+ ],
+ [ // Many-to-one mappings: many Cyrillic to one Latin
+ [
+ 'crh' => 'шофер шофёр şoför корбекул корьбекул корьбекуль körbekül',
+ 'crh-cyrl' => 'шофер шофёр шофёр корбекул корьбекул корьбекуль корьбекуль',
+ 'crh-latn' => 'şoför şoför şoför körbekül körbekül körbekül körbekül',
+ ],
+ 'шофер шофёр şoför корбекул корьбекул корьбекуль körbekül'
+ ],
+ [ // Many-to-one mappings: many Latin to one Cyrillic
+ [
+ 'crh' => 'fevqülade fevqulade февкъульаде beyude beyüde бейуде',
+ 'crh-cyrl' => 'февкъульаде февкъульаде февкъульаде бейуде бейуде бейуде',
+ 'crh-latn' => 'fevqülade fevqulade fevqulade beyude beyüde beyüde',
+ ],
+ 'fevqülade fevqulade февкъульаде beyude beyüde бейуде'
],
];
}
} );
} );
+ QUnit.test( 'getToken() - no query', function ( assert ) {
+ var api = new mw.Api(),
+ // Same-origin warning and missing query in response.
+ serverRsp = {
+ warnings: {
+ tokens: {
+ '*': 'Tokens may not be obtained when the same-origin policy is not applied.'
+ }
+ }
+ };
+
+ this.server.respondWith( /type=testnoquery/, [ 200, { 'Content-Type': 'application/json' },
+ JSON.stringify( serverRsp )
+ ] );
+
+ return api.getToken( 'testnoquery' )
+ .then( function () { assert.fail( 'Expected response missing a query to be rejected' ); } )
+ .catch( function ( err, rsp ) {
+ assert.equal( err, 'query-missing', 'Expected no query error code' );
+ assert.deepEqual( rsp, serverRsp );
+ } );
+ } );
+
QUnit.test( 'getToken() - deprecated', function ( assert ) {
// Cache API endpoint from default to avoid cachehit in mw.user.tokens
var api = new mw.Api( { ajax: { url: '/postWithToken/api.php' } } ),
} );
QUnit.test( 'Integration', function ( assert ) {
- var expected, logSpy, msg;
+ var expected, msg;
expected = '<b><a title="Bold" href="/wiki/Bold">Bold</a>!</b>';
mw.messages.set( 'integration-test', '<b>[[Bold]]!</b>' );
- this.suppressWarnings();
- logSpy = this.sandbox.spy( mw.log, 'warn' );
- assert.equal(
- window.gM( 'integration-test' ),
- expected,
- 'Global function gM() works correctly'
- );
- assert.equal( logSpy.callCount, 1, 'mw.log.warn called' );
- this.restoreWarnings();
-
assert.equal(
mw.message( 'integration-test' ).parse(),
expected,
var text = 'foo тест_#%!\'()[]:<>',
legacyEncoded = 'foo_.D1.82.D0.B5.D1.81.D1.82_.23.25.21.27.28.29.5B.5D:.3C.3E',
html5Encoded = 'foo_тест_#%!\'()[]:<>',
- html5Experimental = 'foo_тест_!_()[]:<>',
// Settings: this is $wgFragmentMode
legacy = [ 'legacy' ],
legacyNew = [ 'legacy', 'html5' ],
newLegacy = [ 'html5', 'legacy' ],
- allNew = [ 'html5' ],
- experimentalLegacy = [ 'html5-legacy', 'legacy' ],
- newExperimental = [ 'html5', 'html5-legacy' ];
+ allNew = [ 'html5' ];
// Test cases are kept in sync with SanitizerTest.php
[
// New world: HTML5 links, legacy fallbacks
[ newLegacy, text, html5Encoded ],
// Distant future: no legacy fallbacks
- [ allNew, text, html5Encoded ],
- // Someone flipped $wgExperimentalHtmlIds on
- [ experimentalLegacy, text, html5Experimental ],
- // Migration from $wgExperimentalHtmlIds to modern HTML5
- [ newExperimental, text, html5Encoded ]
+ [ allNew, text, html5Encoded ]
].forEach( function ( testCase ) {
mw.config.set( 'wgFragmentMode', testCase[ 0 ] );
var text = 'foo тест_#%!\'()[]:<>',
legacyEncoded = 'foo_.D1.82.D0.B5.D1.81.D1.82_.23.25.21.27.28.29.5B.5D:.3C.3E',
html5Encoded = 'foo_тест_#%!\'()[]:<>',
- html5Experimental = 'foo_тест_!_()[]:<>',
// Settings: this is wgFragmentMode
legacy = [ 'legacy' ],
legacyNew = [ 'legacy', 'html5' ],
newLegacy = [ 'html5', 'legacy' ],
- allNew = [ 'html5' ],
- experimentalLegacy = [ 'html5-legacy', 'legacy' ],
- newExperimental = [ 'html5', 'html5-legacy' ];
+ allNew = [ 'html5' ];
[
// Pure legacy: how MW worked before 2017
// New world: HTML5 links, legacy fallbacks
[ newLegacy, text, html5Encoded ],
// Distant future: no legacy fallbacks
- [ allNew, text, html5Encoded ],
- // Someone flipped wgExperimentalHtmlIds on
- [ experimentalLegacy, text, html5Experimental ],
- // Migration from wgExperimentalHtmlIds to modern HTML5
- [ newExperimental, text, html5Encoded ]
+ [ allNew, text, html5Encoded ]
].forEach( function ( testCase ) {
mw.config.set( 'wgFragmentMode', testCase[ 0 ] );
"browser": false
},
"rules":{
- "no-console":0
+ "no-console": 0
}
}
- [Chrome](https://www.google.com/chrome/)
- [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/)
- [Node.js](https://nodejs.org/en/)
-- [MediaWiki-Vagrant](https://www.mediawiki.org/wiki/MediaWiki-Vagrant)
-Set up MediaWiki-Vagrant:
+If using MediaWiki-Vagrant:
cd mediawiki/vagrant
vagrant up
By default, Chrome will run in headless mode. If you want to see Chrome, set DISPLAY
environment variable to any value:
- DISPLAY=:1 npm run selenium
+ DISPLAY=1 npm run selenium
To run only one file (for example page.js), you first need to spawn the chromedriver:
#!/usr/bin/env bash
set -euo pipefail
+# Check the command before running in background so
+# that it can actually fail and have a descriptive error
+hash chromedriver
chromedriver --url-base=/wd/hub --port=4444 &
# Make sure it is killed to prevent file descriptors leak
function kill_chromedriver() {
],
// Patterns to exclude.
exclude: [
- './extensions/CirrusSearch/tests/selenium/specs/**/*.js'
+ relPath( './extensions/CirrusSearch/tests/selenium/specs/**/*.js' )
],
// ============
// See the full list at http://mochajs.org/
mochaOpts: {
ui: 'bdd',
- timeout: 20000
+ timeout: 60000
},
// =====